Search code examples
javaspringspring-mvcjspstruts

Retrieve the values of a nested list from JSP and send it back to form


EDIT Now I know my problem is due to this. The link also provided solutions but I can't seem to figure out how to do it in the 2nd list.

I will first show you the code structure I am working on.

Here is Class MyForm:

public class MyForm extends ValidatorForm {
    private List<ADTO> aDTOList;

    // getters and setters for aDTOList below

    public ADTO getADTO(int index) {
        if (aDTOList == null) {
            aDTOList = new ArrayList<ADTO>();
        }
        if (aDTOList.size() - 1 < index) {
            while (aDTOList.size() - 1 < index) {
                aDTOList.add(new ADTO());
            }
        }
        return aDTOList.get(index);
    }

    @Override
    protected ActionErrors execValidate(ActionMapping mapping, HttpServletRequest request) {
          // BODY NOT SHOWN FOR PRIVACY
    }

    @Override
    public void reset(ActionMapping mapping, HttpServletRequest request) { 
        super.reset(mapping, request);
        this.aDTOList = new ArrayList<ADTO>();
    }


}

Here is Class ADTO:

public class ADTO {
    private List<BDTO> bDTOList;
    // getters and setters for bDTOList below

}

Here is Class BDTO:

public class BDTO {
    private String sample1;
    private String sample2;
    // getters and setters for sample1 and sample2 below

}

I have successfully displayed the contents of aDTOList in the JSP by doing this:

<logic:iterate id="ADTO" name="MyForm" property="aDTOList" indexId="idxRes">
    <logic:iterate id="BDTO" name="ADTO" property="bDTOList" indexId="idxLine">
        <html:hidden name="BDTO" property="sample1" indexed="true"/>
        <html:hidden name="BDTO" property="sample2" indexed="true"/>
    </logic:iterate>
</logic:iterate>

Now my problem is whenever I submit the form bDTOList that is inside aDTOList will become all null.aDTOList has the same size as the original list I have displayed but the only difference is that all elements of bDTOList in a aDTO is null. The structure of the aDTOList is like this if the size of aDTOList is 2 and each ADTO contains bDTOList which also has the size of 2.

[[null, null],[null, null]]

Thus I think my problem is I do not have getBDTO in my form, but I don't know how to implement it. Can anyone help me on how to implement it? Or is there any other means of populating bDTOList with the original data?

NOTE: I CAN'T CHANGE THE STRUCTURE OF THE CODES AND THE CODES ARE JUST SAMPLE CODES


Solution

  • After days of research and tinkering my code I finally was able to retrieve back the values from the JSP and send it back to form. I will just post an answer for future reference. Thanks to this website I was able to know the cause of my problem and eventually made a solution to solve it. Refer below on the details on how I solved my problem.

    I found out that the problem is due to an issue in Commons BeanUtils with indexed properties if you use java.util.List rather than Arrays is that people then get "index out of range" errors with ActionForms that are in Request scope. That is why growing the list when the get(int) method is called is needed to be done. Also you need to reinitialize the list whenever the reset method is called. To do this you need to paste this code in the reset method of the form:

    public void reset(ActionMapping actionMapping, HttpServletRequest httpServletRequest) {
    
        aDTOList = ListUtils.lazyList(new java.util.ArrayList(), new Factory() {
            public Object create() {
                return buildADTOList();
            }
        });
     }
    
    private ADTO buildADTOList() {
        ADTO aDTO = new ADTO();
        List bDTOList = ListUtils.lazyList(new java.util.ArrayList(), new Factory() {
            public Object create() {
                return new BDTO();
            }
        });
        aDTO.setBDTOList(bDTOList);
        return aDTO;
    }
    

    Now your whenever the reset method is called your list will regrow to its original size. The next problem is now how to retrieve back the values from the JSP and place them back in the list. To do this you have to take note of that the value of the resulting html name attribute of your JSP tag must be in this format aDTOList[0].bDTOList[0].sample1. But if you use tag (just as the question was using), the value of the resulting html will look like this: Example:

    <logic:iterate id="ADTO" name="MyForm" property="aDTOList" indexId="idxRes">
        <logic:iterate id="BDTO" name="ADTO" property="bDTOList" indexId="idxLine">
            <html:hidden name="BDTO" property="sample1" indexed="true"/>
            <html:hidden name="BDTO" property="sample2" indexed="true"/>
        </logic:iterate>
    </logic:iterate>
    

    This will result into:

    <input type="hidden" name="BDTO[0].sample1" value="..."/>
    <input type="hidden" name="BDTO[0].sample2" value="..."/>
    <input type="hidden" name="BDTO[1].sample1" value="..."/>
    <input type="hidden" name="BDTO[1].sample2" value="..."/>
    <input type="hidden" name="BDTO[0].sample1" value="..."/>
    <input type="hidden" name="BDTO[0].sample2" value="..."/>
    <input type="hidden" name="BDTO[1].sample1" value="..."/>
    <input type="hidden" name="BDTO[1].sample2" value="..."/>
    

    The result is not in aDTOList[0].bDTOList[0].sample1 format thus you need to use <nested:iterate>.
    The converted code will be:

    <nested:iterate property="aDTOList" indexId="idxRes">
        <nested:iterate property="bDTOList" indexId="idxLine">
            <nested:hidden property="sample1"/>
            <nested:hidden property="sample2"/>
        </nested:iterate>
    </nested:iterate>
    

    This will result to:

    <input type="hidden" name="aDTOList[0].bDTOList[0].sample1" value="..."/>
    <input type="hidden" name="aDTOList[0].bDTOList[0].sample2" value="..."/>
    <input type="hidden" name="aDTOList[0].bDTOList[1].sample1" value="..."/>
    <input type="hidden" name="aDTOList[0].bDTOList[1].sample2" value="..."/>
    <input type="hidden" name="aDTOList[1].bDTOList[0].sample1" value="..."/>
    <input type="hidden" name="aDTOList[1].bDTOList[0].sample2" value="..."/>
    <input type="hidden" name="aDTOList[1].bDTOList[1].sample1" value="..."/>
    <input type="hidden" name="aDTOList[1].bDTOList[1].sample2" value="..."/>
    

    As you can see it is in aDTOList[0].bDTOList[0].sample1 format.

    And from that you can retrieve the values of a nested list from JSP and send it back to form. I hope this will serve as a guide for those people that have been stuck for days solving this kind of problem.