Struts2: Actualización de los valores de una “Lista de objetos” dentro de un Mapa

Hay un objeto ObjectA que tiene una lista de ObjectB . Hay un TreeMap dentro del ObjectB . Este TreeMap tiene una String como clave y una List de otro objeto ObjectC como valor. Este TreeMap y la list interior se han mostrado en jsp usando s:textfield y s:textfield y se muestran correctamente. es decir, los “valores” dentro del campo de texto s: son correctos. Ahora, el problema surge cuando se modifica el campo de texto. ¿Cómo capturamos los valores modificados dentro de ObjectC en la clase de acción? Con el código que se proporciona aquí, la clave (“Key1”) entra en la acción pero el valor es nulo.

Código Java

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

Código JSP

       

HTML procesado:

La estructura del objeto en la vista “Evilidades” del eclipse muestra :

 objA Object A (id=955) objB ArrayList (id=966) elementData Object[10] (id=967) [0] ObjectB (id=968) allPlainFields TreeMap (id=972) comparator null descendingMap null entrySet TreeMap$EntrySet (id=979) keySet null modCount 1 navigableKeySet null root TreeMap$Entry (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 

**** En la vista “Variables” de Eclipse, el valor de allPlainFields es **: ** {Key1 =}

EDITAR (27-feb-2013) :

Intenté esto pero no funcionó. Los valores aparecen en jsp, pero cuando se envían, no entran en acción:

En clase de Action :

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

En la clase ObjectCList :

 private ArrayList paramMdlList; //default constructor, get, set 

En JSP :

   
  • Save TreeMap

    Cuando se envía el formulario, se updateTreeMap método updateTreeMap de la action . El mapa está impreso como se menciona aquí :

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

    }

    Qué es “impreso”: mykey1 / mykey2 / ie valores nulos

    La pantalla a continuación muestra los valores que vienen en jsp pantalla que muestra los valores vienen en jsp

    De acuerdo con tu última actualización. Si está utilizando TreeMap Struts2 no puede determinar correctamente el tipo de elementos dentro de él. Cambia la statement de testTreeMap desde TreeMap a Map .

     private Map testTreeMap = new TreeMap(); 

    O anote testTreeMap con com.opensymphony.xwork2.util.Element annotation para decirle a Struts2 qué tipo son los elementos dentro del mapa.

     @Element(value = ObjectCList.class) private TreeMap testTreeMap = new TreeMap(); 

    Me he vuelto curioso e hice otros experimentos.

    Descubrí que ni List ‘s dentro de List s, ni Map s dentro de Map s (y todas las interpolaciones), declaradas como interfaz ( List , Map ), o que sus implementaciones ( ArrayList , HashMap , TreeMap ) son manejadas correctamente por XWork Converter .

    Todos los casos de prueba han fallado.

    Tal vez es mi culpa, si es así, realmente necesitamos algunos expertos de OGNL aquí, porque en toda la web no se habla de esto.

    Luego probé lo que estaba bastante seguro de que hubiera funcionado: encapsulando esta información en objetos personalizados , en forma OOP pura.

    Y funcionó 🙂

    En lugar de

     private ArrayList> outerObjects; 

    puedes usar en tu Acción

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

    la definición de OuterObject :

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

    la definición de InnerObject :

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

    el método opcional execute () de su acción para probar los valores preestablecidos:

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

    el JSP :

          

    (Al iterar, simplemente use [%{#stat.index}] para List s y ['%{#stat.index}'] para Map s)

    La misma solución es aplicable para todo tipo de estructura iterable (probablemente, excepto el material de Guava que necesita el método .create() para ser invocado).

    Por supuesto, esto no es práctico en todos los casos, en tu ejemplo ya tienes una estructura enorme y esto casi duplicará , pero funciona, es OOP, tu OGNL será más claro (por los nombres) y sin embargo parece ser el único camino.

    Nota: las clases deben ser clases autónomas reales, no Inner Classes , otro caso donde OGNL no puede conectar automáticamente los objetos.

    Espero que ayude


    EDITAR

    Lo que necesitas entonces, es solo un nivel más:

    cambia esto:

     private TreeMap> allPlainFields; 

    a esto

     private TreeMap allPlainFields; 

    y crea un ObjectX contiene un campo privado que es una List .

    Funcionará.