javajspstruts2model-driven

How to access properties in the POJO using Struts 2 ModelDriven interface when you are using JSP?


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 calledPersonand my person has an attribute calledAddressthat is another object.Addresshas regular properties such asString, 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.


Solution

  • 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.