3

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.

Roman C
  • 49,761
  • 33
  • 66
  • 176
Philippe Gioseffi
  • 1,488
  • 3
  • 24
  • 41

1 Answers1

1

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.

Roman C
  • 49,761
  • 33
  • 66
  • 176
  • Roman C, if you check my edit you'll see that I have a object called FakeDTO and this object has a FakeFilterDTO just the way you designed. I haven't posted my struts.xml because I thought it wouldn't be necessary since I've said that regular properties such as String, Long, Integer and etc are properly mapped. Thanks for your help and time though. – Philippe Gioseffi Nov 29 '13 at 15:45
  • I've seen you edits but nothing from it is related to the `address` property and `AddressDTO`. So, you don't have a property, your code doesn't have a mapping. Nothing changed in my answer. – Roman C Nov 29 '13 at 16:16
  • That's because Person and Address I used as concrete examples that would make easier to understand for everybody. If you compare the code with the situation I described you'll figure out that Person is similar to FakeDTO object being the main DTO and FakeFilterDTO is similiar to the Address being the inner DTO. – Philippe Gioseffi Nov 29 '13 at 16:26
  • The expression in JSP also similar? – Roman C Nov 29 '13 at 16:33
  • Yes, the JSP is similar too. I formatted incorrectly my edit in the end and the new code for the JSPs weren't showing. If you read again you'll see that yesterday I wrote "The JSP that I used as an example before would become as follows:" but the code isn't there. I'll edit and correct now. Thanks a lot for your effort. – Philippe Gioseffi Nov 29 '13 at 16:38
  • Do you check the value on submit in action? And what version of Struts? – Roman C Nov 29 '13 at 16:47
  • What do you mean if I check the value on submit? If I use the validate method? Or if I use jquery plugins to validate the forms? I don't use the backend validation because I hava a jQuery plugin validating the entries for me in the client side and the system will not be accessible on the internet so we do not have to validate in the backend again. The Struts versin that I'm using is 2.2.3.1. – Philippe Gioseffi Nov 29 '13 at 16:54
  • So, how can you check that value in the action when it's populated? – Roman C Nov 29 '13 at 17:06
  • When I get in the DAO layer my object has the regular properties set and ready to use, but the Address, a.k.a. FakeFilterDTO, have all its properties nulled. – Philippe Gioseffi Nov 29 '13 at 17:09
  • I don't talk about DAO stay at the View -> Controller. – Roman C Nov 29 '13 at 17:13
  • I didn't understand your question, the way I check the values in my POJO is placing a break point after submitting the form and inspecting the object. That's how I check the values. – Philippe Gioseffi Nov 29 '13 at 17:15
  • Good, now post the `struts.xml`. – Roman C Nov 29 '13 at 17:17
  • Roman C, I posted the struts.xml. Something came across my mind right now and I'll test and check it. We submit the form using jQuery.ajax using method POST, I'll try to post with regular submit and check if it works. – Philippe Gioseffi Nov 29 '13 at 17:30
  • Roman C, thanks for your help. The problem is that ModelDriven does not work with Ajax. If we submit the form it works. – Philippe Gioseffi Nov 29 '13 at 17:55
  • In you question you didn't show that you are using Ajax and even if you do you are doing something wrong because ModelDriven doesn't relate to the type of request you perform. – Roman C Nov 29 '13 at 18:25
  • Yes, in my question I forgot to inform that. But, actually, ModelDriven does relate to the type of request. I just did the test. If we submit the form with Ajax ModelDriven does not work, submitting with a regular submit button inside a form got the properties mapped correctly. – Philippe Gioseffi Nov 29 '13 at 18:35
  • I don't know if this has something to do with my problem, but may be related, checkout this issue reported: https://issues.apache.org/jira/browse/WW-2721 – Philippe Gioseffi Nov 29 '13 at 18:39
  • This is old bug related JSONValidation interceptor and not your case. – Roman C Nov 29 '13 at 18:48
  • Probably not, but there are other bugs related to ModelDriven and Ajax. Do you think this could be another one? – Philippe Gioseffi Nov 29 '13 at 19:03
  • I don't think so, you didn't post the code. Ajax submit works the same as non-Ajax. – Roman C Nov 29 '13 at 19:05
  • The code that is not working to you is Ajax as I understand, right? – Roman C Nov 29 '13 at 19:32
  • Roman C, you can kill me now. The problem was not with the Ajax request nor the ModelDriven. The Ajax that we wrote didn't have the data attribute declared, then nothing was going to the server and the struts framework couldn't bind with the data with the ModelDriven. – Philippe Gioseffi Nov 29 '13 at 19:35
  • So, everything is ok now? – Roman C Nov 29 '13 at 19:40
  • Yes, everything is OK, now! Once again thank you very much for yout time and effort. – Philippe Gioseffi Nov 29 '13 at 20:03
  • Roman C, I'm still getting how to interact here in StackOverFlow, should I create an answer explaining what I was doing wrong? – Philippe Gioseffi Nov 29 '13 at 20:04
  • How to interact is [here](http://stackoverflow.com/about), If the answer helped you to solve the problem then you should mark it as accepted, you can also upvote the answer if you like it. – Roman C Nov 29 '13 at 20:11
  • I can't upvote my own question. Your answer and later our comments helped me to achieve the solution, but the answer itself if marked as the accepted one may lead others to a wrong solution, don't you think? Or I can mark this answer as the accepted one because of the comments that led us to the solution? – Philippe Gioseffi Nov 29 '13 at 20:15
  • Yes, I think you understood now, because the effort is a value that is expected on SO. – Roman C Nov 29 '13 at 20:18