Hi again,

I was thinking about this again a few minutes ago and thought maybe using
an object that implements Map is not the solution, maybe if I use a List
implementation, then OGNL will not interpret ".value" as get("value") since
you can't do that to a List.
Indeed getValue() was called using a List implementation, but during the
set phase, setValue() isn't called.

After a bit more exploring, I think I found myself a bit of a
workaround/solution.

class MyMap implements Map {

private Long id;

public MyMap(Long id) {
this.id = id;
}

public Object get(Object key) {
System.out.println("MyMap@" + id + ".get(" + key + ")");
return new MyMap(id + 1);
}

public Object put(Object key, Object value) {
System.out.println("MyMap@" + id + ".put(" + key + "," + value + ")");
return null;
}

...

}

This code in the jsp seems to work for both get and set

<s:textfield name="fieldMap['%{index}']"/>

During get

>> getIndex()
>> getFieldMap()
my...@1.get(1)
>> getIndex()

During set

>> getFieldMap()
my...@1.put(1,[Ljava.lang.String;@3354a944)

Therefore, using my previous example, this should work

<s:textfield name="fieldMap['1']"/> or <s:textfield
name="fieldMap['CASUAL_1']"/>
gets and sets gameConsole of userId = 1, MyMap should be able to look at
the key, parses it (sees that it is only 1 id) and gets/sets accordingly

<s:textfield name="fieldMap['2_9']"/> or <s:textfield
name="fieldMap['AVERAGE_2_9']"/>
gets and sets gameName of gameId = 9 of userId = 2, again MyMap should be
able to look at the key, parses it (sees that it is 2 ids) and gets/sets
accordingly


On Tue, May 20, 2014 at 6:26 PM, Christoph Nenning <
christoph.nenn...@lex-com.net> wrote:

> > 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
>

Reply via email to