Hello,
I have some problems to understand if there are some differences in how form/model binding works in Spring MVC / Spring Web Flow; in particular when I use "complex" models (nested entities).
I'm so sorry, but I wasn't able to find relevant documentation about possible differences, so let me explain through a very simple example.
First, MVC case; then Web Flow case.
Environment: SWF 2.3.1.RELEASE + Spring 3.1.0.RELEASE
*** MVC case ***
I have two objects: Bogus and NestedBogus
First object: Bogus
Second object: NestedBogusCode:package org.sbibiz.mvcjpa.bogus; import java.io.Serializable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class Bogus implements Serializable { private static final long serialVersionUID = 1L; private static final Logger logger = LoggerFactory.getLogger(Bogus.class); public Bogus() { // NOTICE THE LOGGER HERE! logger.info("Bogus Constructor called"); } private String id; private String name; private NestedBogus nestedBogus; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public NestedBogus getNestedBogus() { return nestedBogus; } public void setNestedBogus(NestedBogus nestedBogus) { this.nestedBogus = nestedBogus; } }
I have this controller (GET snippet):Code:package org.sbibiz.mvcjpa.bogus; import java.io.Serializable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class NestedBogus implements Serializable { private static final long serialVersionUID = 1L; private static final Logger logger = LoggerFactory .getLogger(NestedBogus.class); public NestedBogus() { // NOTICE THE LOGGER HERE! logger.info("Nested Bogus Constructor called"); } private String id; private String name; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
And the view (FORM snippet):Code:@RequestMapping(value = "/bogus", method = RequestMethod.GET) public String ordering_GET(Locale locale, Model model) { model.addAttribute("myBogus", new Bogus()); return "bogus"; }
EVERYTHING WORKS FINE!HTML Code:<sf:form action="${myURL}" method="post" modelAttribute="myBogus"> bogus.id: <sf:input path="id"/><br/> bogus.name: <sf:input path="name"/><br/> bogus.nestedBogus.id: <sf:input path="nestedBogus.id"/><br/> bogus.nestedBogus.name: <sf:input path="nestedBogus.name"/> <input type="submit" value="Go, Bogus! Go!" /> </sf:form>
And the logger says to me:
INFO : org.sbibiz.mvcjpa.bogus.Bogus - Bogus Constructor called
INFO : org.sbibiz.mvcjpa.bogus.NestedBogus - Nested Bogus Constructor called
*** SWF case ***
In a flow, now, I have this view state (conf snippet):
When I request the flow... EVERYTHING STOPS WORKING... :-(HTML Code:<var name="myBogus" class="org.sbibiz.mvcjpa.bogus.Bogus" /> ... <view-state id="start" view="bogus" model="myBogus"> ... </view-state>
And I get:
It seems to me that in the first case Spring "takes care" to set up the model properly.Code:INFO : org.sbibiz.mvcjpa.bogus.Bogus - Bogus Constructor called ERROR: org.springframework.web.servlet.tags.form.InputTag - An ELException occurred getting the value type for expression 'nestedBogus.id' on context [class org.sbibiz.mvcjpa.bogus.Bogus] org.springframework.binding.expression.EvaluationException: An ELException occurred getting the value type for expression 'nestedBogus.id' on context [class org.sbibiz.mvcjpa.bogus.Bogus] at org.springframework.binding.expression.spel.SpringELExpression.getValueType(SpringELExpression.java:105) at org.springframework.webflow.mvc.view.BindingModel.getFormattedValue(BindingModel.java:228) at org.springframework.webflow.mvc.view.BindingModel.getFieldValue(BindingModel.java:142) at org.springframework.web.servlet.support.BindStatus.<init>(BindStatus.java:120) at org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.getBindStatus(AbstractDataBoundFormElementTag.java:178) at org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.getPropertyPath(AbstractDataBoundFormElementTag.java:198) at org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.getName(AbstractDataBoundFormElementTag.java:164) at org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.autogenerateId(AbstractDataBoundFormElementTag.java:151) at org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.resolveId(AbstractDataBoundFormElementTag.java:142) at org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.writeDefaultAttributes(AbstractDataBoundFormElementTag.java:126) [...] Caused by: org.springframework.expression.spel.SpelEvaluationException: EL1007E:(pos 12): Field or property 'id' cannot be found on null at org.springframework.expression.spel.ast.PropertyOrFieldReference.readProperty(PropertyOrFieldReference.java:205) at org.springframework.expression.spel.ast.PropertyOrFieldReference.getValueInternal(PropertyOrFieldReference.java:72) at org.springframework.expression.spel.ast.CompoundExpression.getValueInternal(CompoundExpression.java:57) at org.springframework.expression.spel.standard.SpelExpression.getValueType(SpelExpression.java:117) at org.springframework.binding.expression.spel.SpringELExpression.getValueType(SpringELExpression.java:100) ... 71 more [...]
In the second one, I'm able to make it work only if I modify Bogus.java a little: private NestedBogus nestedBogus = new NestedBogus(); But that's not what I'd like...
Am I wrong? Have I forgot something? Or what am I ignoring?
Thank you very much!
Regards.


Reply With Quote
