Struts2: Updating Object List Values ​​Inside a Map

There is an ObjectA object that has an ObjectB list. ObjectB has a TreeMap . This TreeMap has the String as and List key of another ObjectC object as a value. This TreeMap and List inside is displayed on jsp using s:iterator and s:textfield , and it displays correctly. that is, the "values" inside the s: text field are correct. Now the problem occurs when changing the text field. How do we commit changed values ​​inside an ObjectC in an action class? With the code shown here, the key ("Key1") comes into effect, but the value is null.

Java code

 public class ObjectA implements Serializable { private Integer attr1; private List<ObjectB> objB; //...getters and setters.... public class ObjectB implements Serializable { private Integer attr11; private TreeMap<String,List<ObjectC>> allPlainFields; // ...getters and setters.... public class ObjectC implements Serializable { private Integer attr111; public String attr112; // ...getters and setters.... 

JSP code

 <s:iterator value="objA.objB" var="currentObjB" status="currentGroupStatus"> <s:iterator value="#currentObjB.allPlainFields" var="parentMap" status="headerStatus"> <s:iterator value="#parentMap.value" var="fieldList" status="fieldStatus"> <s:textfield name="objA.objB[%{#currentGroupStatus.index}].allPlainFields['%{#parentMap.key}'][%{#fieldStatus.index}].attr112"/> </s:iterator> </s:iterator> 

Presented HTML: <input type="text" id="review-act1_objA_objB_0__allPlainFields_'Key1'__6__attr112" value="Correct Value" name="objA.objB[0].allPlainFields['Key1'][0].attr112">

The structure of the object in the Captures view in eclipse shows :

 objA Object A (id=955) objB ArrayList<E> (id=966) elementData Object[10] (id=967) [0] ObjectB (id=968) allPlainFields TreeMap<K,V> (id=972) comparator null descendingMap null entrySet TreeMap$EntrySet (id=979) keySet null modCount 1 navigableKeySet null root TreeMap$Entry<K,V> (id=980) size 1 values null [1] ObjectB (id=969) [2] ObjectB (id=970) [3] ObjectB (id=971) [4] null [5] null [6] null [7] null [8] null [9] null modCount 4 size 4 

**** In the Eclipse Variables view, the value for allPlainFields is **: ** {Key1 =}

EDIT (27-Feb-2013)

Tried this but didn't work. The values ​​appear on jsp, but when they are submitted, they do not take effect:

In Action class:

 private TreeMap<String,ObjectCList> testTreeMap = new TreeMap<String,ObjectCList>(); //get,set and setting two keys in map "mykey1" and "mykey2" 

In the ObjectCList class:

 private ArrayList<ObjectC> paramMdlList; //default constructor, get, set 

In jsp :

 <s:form id="test-map" method="post"> <s:iterator value="testTreeMap" var="pMap" status="hStatus"> <li><label><s:property value="%{#pMap.key}" /></label> <s:iterator value="%{#pMap.value.paramMdlList}" var="pList" status="innerStatus"> <s:textfield name="testTreeMap['%{#pMap.key}'].paramMdlList[%{#innerStatus.index}].attr111"/> <s:textfield name="testTreeMap['%{#pMap.key}'].paramMdlList[%{#innerStatus.index}].attr112"/> </s:iterator> </li> </s:iterator> <s:submit value=" " type='button' id="btnh1" action="saveTreeMap"> <span>Save TreeMap</span> </s:submit> </s:form> 

When submitting the form, the updateTreeMap Action method is updateTreeMap . The map is printed as indicated here :

 public String updateTreeMap(){ for (Map.Entry<String, ObjectCList> entry : testTreeMap.entrySet()) { System.out.println(entry.getKey() + "/" + entry.getValue()); } return SUCCESS; 

}

What is "printed": mykey1 / mykey2 / that is, zero values

The screen below shows the values ​​coming in jsp screen showing values ​​come in jsp

+6
source share
2 answers

According to your latest update. If you use TreeMap , Struts2 cannot correctly determine the type of elements inside it. Change the declaration of testTreeMap from TreeMap to Map .

 private Map<String,ObjectCList> testTreeMap = new TreeMap<String,ObjectCList>(); 

Or annotate testTreeMap with annotation com.opensymphony.xwork2.util.Element to tell Struts2 which types are elements within the map.

 @Element(value = ObjectCList.class) private TreeMap<String,ObjectCList> testTreeMap = new TreeMap<String,ObjectCList>(); 
+6
source

I became curious about other experiments.

I found that neither List inside List s, nor Map inside Map (and all interpolations) declared as an interface ( List , Map ), or how their implementations ( ArrayList , HashMap , TreeMap ) are correctly processed by XWork Converter .

All test cases failed.

Perhaps it’s my fault if we really need OGNL experts here, because the whole network says nothing about it.

Then I tried what I was sure it would work: encapsulating this information in user objects , in a pure OOP way.

And it worked :)

Instead

 private ArrayList<ArrayList<String>> outerObjects; 

you can use in your action

 private ArrayList<OuterObject> outerObjects; /* GETTERS AND SETTERS */ public ArrayList<OuterObject> getOuterObjects() { return outerObjects; } public void setOuterObjects(ArrayList<OuterObject> outerObjects) { this.outerObjects = outerObjects; } 

OuterObject definition:

 /* ELSEWHERE IN YOUR PROJECT... */ public class OuterObject{ private ArrayList<InnerObject> innerObjects; /* GETTERS AND SETTERS */ public ArrayList<InnerObject> getInnerObjects() { return innerObjects; } public void setInnerObjects(ArrayList<InnerObject> innerObjects) { this.innerObjects = innerObjects; } } 

InnerObject definition:

 public class InnerObject{ String innerField; /* GETTERS AND SETTERS */ public String getInnerField() { return innerField; } public void setInnerField(String innerField) { this.innerField = innerField; } } 

an optional execute () method of your Action to check for predefined values:

  InnerObject innerObj1 = new InnerObject(); innerObj1.setInnerField("Inner Value 1"); ArrayList<InnerObject> innerObjArrayList = new ArrayList<InnerObject>(); innerObjArrayList.add(innerObj1); OuterObject outerObj1 = new OuterObject(); outerObj1.setInnerObjects(innerObjArrayList); outerObjects = new ArrayList<OuterObject>(); outerObjects.add(outerObj1); 

JSP :

  <s:form> <s:textfield name="outerObjects[0].innerObjects[0].innerField" /> <s:submit/> </s:form> 

(during iteration, just use [%{#stat.index}] for List and ['%{#stat.index}'] for Map s)

The same solution applies for each type of iterative structure (possibly, except for Guava material, which requires the .create() method to be called).

Of course, this is not convenient in every case, in your example you already have a huge structure , and it will almost double it , but it works, it is OOP, your OGNL will be more understandable (because of names) and, nevertheless, it seems the only one way.

Note. Classes must be real autonomous classes, not Inner Classes , in another case where OGNL cannot auto-increment objects.

Hope that helps


EDIT

Then you need only one level:

change this:

 private TreeMap<String,List<ObjectC>> allPlainFields; 

to that

 private TreeMap<String,ObjectX> allPlainFields; 

and create an ObjectX containing a private field that is List<ObjectC> .

He will work.

+5
source

All Articles