> 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. >
I had bad experience with more complex ONGL expressions like the following in own applications (other issues with that are registering typeConverters and validators): <s:textfield name="wonky['1'].value"/> <s:textfield name="wonky['1']['9'].value"/> <s:textfield name="wonky['1'].value['9'].value"/> Usually I define several maps in the action, like this: Map<userId, gameConsole> gamerConsoles Map<userId, type> gamerConsoleTypes Map<userId, gameId> gamerGames ... Regards, Christoph > > 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 > > This Email was scanned by Sophos Anti Virus