I have an action class that implements ModelDriven
interface. This ModelDriven
is a regular POJO, the problem is that one of its properties is another object.
Imagine that my ModelDrivenis a object called
Personand my person has an attribute called
Addressthat is another object.
Addresshas regular properties such as
String,
Long` and etc.
In the JSP when I submit the form, all the regular properties used such as String
, int
, long
in Person
are mapped correctly, but all the data that should be mapped to address are not.
<s:textfield name="name" id="name" size="25" maxlength="15" />
<s:textfield name="address.zipcode" id="zipcode" size="25" maxlength="15" />
That's how I try mapping the properties. The name property I can get it right, but when it comes to map the properties in the person's address this approach does not work.
What am I doing wrong?
In time, my Address
property is declared in Person
instantiating the object, so it's never null
.
EDIT: As requested, here the action source and the DTOs:
The Action:
@Controller
@Scope("request")
public class AnAction extends BaseAction implements ModelDriven<FakeDTO> {
private static final long serialVersionUID = 8238033889271514835L;
@Autowired
private FakeFacade facade;
private FakeDTO fakeDTO = new FakeDTO();
public String action01() {
return Action.SUCCESS;
}
public String action02() {
this.fakeDTO.setAnswer(this.fakeFacade.fakeFacadeMethod(this.fakeDTO.getComplexObject()));
return Action.SUCCESS;
}
@Override
public FakeDTO getModel() {
return this.fakeDTO;
}
}
The main class FakeDTO
:
public class FakeDTO implements BaseDTO {
private static final long serialVersionUID = -2093038083351846003L;
private FakeFilterDTO filter = new FakeFilterDTO();
private String name;
public FakeDTO() {
super();
}
@Override
public FakeFilterDTO getFilter() {
return this.filter;
}
public void setFilter(final FakeFilterDTO filterParam) {
this.filter = filterParam;
}
public String getName() {
return this.name;
}
public String setName(final String nameParam) {
this.name = nameParam;
}
}
The class FakeFilterDTO
:
public class FakeFilterDTO extends BaseFilterDTO {
private static final long serialVersionUID = 4528040257605851210L;
private Date aDate;
private Long aLong;
private Integer anInteger;
private String aString;
public Date getADate() {
return this.aDate;
}
public void setDataInicial(final Date aDateParam) {
this.aDate = aDateParam;
}
public Long getALong() {
return this.aLong;
}
public void setALong(final Long aLongParam) {
this.aLong = aLongParam;
}
public Integer getAnInteger() {
return this.anInteger;
}
public void setAnInteger(final Integer anIntegerParam) {
this.anInteger = anIntegerParam;
}
public String getAString() {
return this.aString;
}
public void setAString(final String aStringParam) {
this.aString = aStringParam;
}
}
The struts.xml
:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.1.7//EN"
"http://struts.apache.org/dtds/struts-2.1.7.dtd">
<struts>
<include file="META-INF/bsad/struts2/struts-config.xml" />
<package name="reports" namespace="/reports" extends="project-default">
<action name="anAction" class="anAction" method="action01">
<result>/WEB-INF/pages/success.jsp</result>
<result name="input">/WEB-INF/pages/input.jsp</result>
</action>
<action name="generateReport" class="anAction" method="action02">
<result>/WEB-INF/pages/reportGenerated.jsp</result>
</action>
</package>
</struts>
The project-default
is placed in the include struts-config.xml
and extends struts-default
package that contains the ModelDrivenInterceptor
. I can assure that because I placed a break point in this interceptor and its passing through there.
The JSP that I used as an example before would become as follows:
<s:textfield name="name" id="name" size="25" maxlength="15" />
<s:textfield name="filter.aString" id="zipcode" size="25" maxlength="15" />
For company policies I'm not allowed to copy/paste the actual objects and its names. But that's the idea.
In the fakeDTO
that is your model you should have a property address
which should return an object like AddressDTO
in this object there should be a property zipcode
.
public class FakeDTO implements BaseDTO {
private AddressDTO address;
public AddressDTO getAddress() {
return address;
}
public void setAddress (AddressDTO address) {
this.address = address;
}
...
}
public class AddressDTO implements BaseDTO {
private String zipcode;
public String getZipcode() {
return zipcode;
}
public void setZipcode(String zipcode) {
this.zipcode = zipcode;
}
...
}
as you haven't posted struts.xml
your action configuration should include modelDriven
interceptor which include in the defaultStack
by default is used when you extend struts-default
package. See example of using ModelDriven
. The model is pushed to the top
of the valueStack
by the interceptor, so the object like address
should be available if it has a default constructor it will be created by the OGNL and zipcode
set there. When you display the fields in the JSP the address.zipcode
is evaluated as an OGNL expression and retrieve zipcode
from the address bean if the model is initialized that bean and zipcode itself. All beans referenced in OGNL expression should be initialized and have getter/setter properties.