My case is logically like this Imagine these data structure
gamer: userId gameConsole type game: gameId gameName A game is associated to a gameConsole There are 2 types of gamers, for a type = CASUAL gamer, there are no games associated for a type = AVERAGE gamer, you can have games asscociated Data as follows userId: 1 gameConsole: nintendo type: CASUAL userId: 2 gameConsole: playstation type: AVERAGE gameId: 9, gameName: Gran Turismo gameId: 10, gameName: Winning Eleven Imagine I have a bean class called Wonky (that implements java.util.Map) that behaves like this Type = CASUAL Wonky.get(String key) will return a Wonky instance, if you then call getValue() on this instance it will return a gameConsole name (e.g. nintendo or playstation) Type = AVERAGE Wonky.get(String key) will return a Wonky instance, if you then call get(String key) on this instance it will return another Wonky instance, if you then call getValue() on this instance it will return a game name (e.g Gran Turismo or Winning Eleven) I want to be able to do this on a form <s:textfield name="wonky['1'].value"/> During get: shows the gameConsole of gamer with userId = 1 During set: sets the gameConsole for gamer with userId = 1 <s:textfield name="wonky['1']['9'].value"/> During get: shows the game with id = 9 associated with gamer with userId = 1 During set: set the game name with id = 9 associated with gamer with userId = 1 alternatively, I'm ok with this idea as well <s:textfield name="wonky['1'].value['9'].value"/> In this case Wonky behaves like this for Type = AVERAGE Wonky.get(String key) -> Wonky instance, getValue() -> return this; get(String key) -> another Wonky instance, getValue() on that instance will return a game name (e.g Gran Turismo or Winning Eleven) I did more investigation Consider this code class MyMap implements Map { private Long id; public MyMap(Long id) { this.id = id; } ... @Override public Object get(Object key) { System.out.println("MyMap@" + id + ".get(" + key + ")"); return new MyMap(id + 1); } public String getValue() { System.out.println("MyMap@" + id + ".getValue()"); return Long.toString(id); } public void setValue(String value) { System.out.println("MyMap@" + id + ".setValue(" + value + ")"); } } On my action class public MyMap getFieldMap() { System.out.println(">> getFieldMap()"); MyMap map = new MyMap(1L); return map; } public void setFieldMap(MyMap map) { } private Long index = 1L; public Long getIndex() { System.out.println(">> getIndex()"); return index; } public void setIndex(Long index) { System.out.println(">> setIndex(" + index + ")"); this.index = index; } On my jsp <s:form action="..."> <s:textfield name="fieldMap['%{index}']['%{index}'].value"/> <s:submit/> </s:form> Result is During get >> getIndex() >> getIndex() >> getFieldMap() my...@1.get(1) my...@2.get(1) my...@3.get(value) >> getIndex() >> getIndex() Ok, getValue() isn't called, I can work with this, I can make all my keys numbers, if I detect a non-number I just route the call to getValue() I think since it implements a map, ".value" get interpreted as get("value"); During set >> getFieldMap() my...@1.get(1) my...@2.get(1) This I can't work with since setValue() isn't called anywhere. On Tue, May 20, 2014 at 3:02 PM, Christoph Nenning < christoph.nenn...@lex-com.net> wrote: > > Question: > > According to OGNL ( > > http://commons.apache.org/proper/commons-ognl/language-guide.html) under > > heading JavaBeans Indexed Properties and OGNL Object Indexed Properties, > > getFieldWithIndex(int index) should be called, but it isn't, same goes > with > > getFieldWithKey(String key), why ? > > I looked at the latest OGNL source code (not the one I'm using since I > > couldn't find the source code for version 3.0.6) hoping if I could spot > a > > method where it tries different get/set methods. > > Tried setting breakpoints at OGNLRuntime, ObjectPropertyAccessor but > > coulnd't see anything obvious. > > > > At the moment I have a few workarounds > > 1. Use the ones that are working, i.e. getFieldList() and getFieldMap(), > > implementing my own List and Map > > > Another way would be OGNL method call syntax: > > <s:property value="getFieldWithIndex(1)"/> > > > > > > > 2. Use java.util.List getList() and setList(java.util.List list), struts > > will create a new List and populate accordingly in the order in which > they > > were submitted in the form > > The issue with this is, if I have a pair or triplet of things that go > hand > > in hand, then it gets complex. > > e.g. > > name and address where address is optional > > in the form the user put name1, address1, name2 (with no address), and > > name3, address3 > > struts calls setName() with List containing name1, name2, name3 > > it also calls setAddress() with List containing address1, address3 > > There is no way the code can then figure out that that address3 is > actually > > associated with name3 > > In the past I was able to get around this by supplying another data > > structure that tells the code which address belongs to which name but it > > involves JavaScript, and it gets messy quite quickly. > > > > struts/OGNL can store mulitple values in a map. You could use name as key > and address as value: > > address: <s:textfield name="map['name']" /> > > That works well when you know names during "get phase" (when users cannot > change names on that particular form). > If users can also enter names here, you need javascript. > > Another use case of that map syntax is when the number of input fileds is > dynamic. > > > > > > 3. "Bypass" struts, in the "get" phase (showing the form) just use > straight > > html combined with struts tags, during the "set" phase (submitting the > > form), will just get the parameters using HttpServletRequest > > e.g. during show form > > <input type="text" name="whateverName" value="<s:property > > value="whateverValue"/>"/> > > instead of > > <s:textfield ... /> > > > This is always possible, of course. It means you have to generate > parameter names during GET and parse them on POST. > > Usually I try to avoid this in my applications but there are (rare) cases > I need to do that. > If you do so, you have to think of how you do validation. You can still > use struts validation when you generate the same parameter names again (in > validate() method) and use <s:fieldError> tags with the same generated > names. > > > > > > Regards, > Christoph > > > > > > > > > > OGNL Indexed and Object Indexed Properties > > > > Hi, > > > > I'm wondering why this code is not working. I'm using struts 2.3.16.1 > and > > ognl 3.0.6. > > > > In my action class I have this > > > > public String[] getFieldArray() { > > System.out.println(">> getFieldArray()"); > > return null; > > } > > > > public void setFieldArray(String[] array) { > > } > > > > public MyList<String> getFieldList() { > > System.out.println(">> getFieldList()"); > > return new MyList<String>(); > > } > > > > public void setFieldList(MyList<String> list) { > > } > > > > public MyMap<String, String> getFieldMap() { > > System.out.println(">> getFieldMap()"); > > return new MyMap<String, String>(); > > } > > > > public void setFieldMap(MyMap<String, String> map) { > > > > } > > > > public String getFieldWithIndex(int index) { > > System.out.println(">> getFieldWithIndex(" + index + ")"); > > return null; > > } > > > > public void setFieldWithIndex(int index, String value) { > > System.out.println(">> setFieldWithIndex(" + index + "," + value + ")"); > > } > > > > public String getFieldWithKey(String key) { > > System.out.println(">> getFieldWithKey(" + key + ")"); > > return null; > > } > > > > public void setFieldWithKey(String key, String value) { > > System.out.println(">> setFieldWithKey(" + key + "," + value + ")"); > > } > > > > Note that MyList and MyMap are as follows > > > > class MyMap<K, V> implements Map<K, V> { ... } > > class MyList<V> implements List<V> { ... } > > > > I have the get() methods overridden on the those classes > > > > On my jsp I have this > > > > <s:property value="fieldArray[1]"/> > > <s:property value="fieldList[1]"/> > > <s:property value="fieldMap['1']"/> > > <s:property value="fieldWithIndex[1]"/> > > <s:property value="fieldWithKey['1']"/> > > > > Result is > > > > >> getFieldArray() > > >> getFieldList() > > MyList.get(1) > > >> getFieldMap() > > MyMap.get(1) > > MyMap.get(1) > > > > Question: > > According to OGNL ( > > http://commons.apache.org/proper/commons-ognl/language-guide.html) under > > heading JavaBeans Indexed Properties and OGNL Object Indexed Properties, > > getFieldWithIndex(int index) should be called, but it isn't, same goes > with > > getFieldWithKey(String key), why ? > > I looked at the latest OGNL source code (not the one I'm using since I > > couldn't find the source code for version 3.0.6) hoping if I could spot > a > > method where it tries different get/set methods. > > Tried setting breakpoints at OGNLRuntime, ObjectPropertyAccessor but > > coulnd't see anything obvious. > > > > At the moment I have a few workarounds > > 1. Use the ones that are working, i.e. getFieldList() and getFieldMap(), > > implementing my own List and Map > > > > 2. Use java.util.List getList() and setList(java.util.List list), struts > > will create a new List and populate accordingly in the order in which > they > > were submitted in the form > > The issue with this is, if I have a pair or triplet of things that go > hand > > in hand, then it gets complex. > > e.g. > > name and address where address is optional > > in the form the user put name1, address1, name2 (with no address), and > > name3, address3 > > struts calls setName() with List containing name1, name2, name3 > > it also calls setAddress() with List containing address1, address3 > > There is no way the code can then figure out that that address3 is > actually > > associated with name3 > > In the past I was able to get around this by supplying another data > > structure that tells the code which address belongs to which name but it > > involves JavaScript, and it gets messy quite quickly. > > > > 3. "Bypass" struts, in the "get" phase (showing the form) just use > straight > > html combined with struts tags, during the "set" phase (submitting the > > form), will just get the parameters using HttpServletRequest > > e.g. during show form > > <input type="text" name="whateverName" value="<s:property > > value="whateverValue"/>"/> > > instead of > > <s:textfield ... /> > > This Email was scanned by Sophos Anti Virus >