You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@struts.apache.org by foo bar <li...@gmail.com> on 2014/05/20 09:43:31 UTC
OGNL Indexed and Object Indexed Properties
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 ... />
Re: OGNL Indexed and Object Indexed Properties
Posted by foo bar <li...@gmail.com>.
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()
MyMap@1.get(1)
>> getIndex()
During set
>> getFieldMap()
MyMap@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.Nenning@lex-com.net> wrote:
> > Result is
> >
> > During get
> >
> > >> getIndex()
> > >> getIndex()
> > >> getFieldMap()
> > MyMap@1.get(1)
> > MyMap@2.get(1)
> > MyMap@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()
> > MyMap@1.get(1)
> > MyMap@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()
> > MyMap@1.get(1)
> > MyMap@2.get(1)
> > MyMap@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()
> > MyMap@1.get(1)
> > MyMap@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.Nenning@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
>
Re: OGNL Indexed and Object Indexed Properties
Posted by Christoph Nenning <Ch...@lex-com.net>.
> Result is
>
> During get
>
> >> getIndex()
> >> getIndex()
> >> getFieldMap()
> MyMap@1.get(1)
> MyMap@2.get(1)
> MyMap@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()
> MyMap@1.get(1)
> MyMap@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()
> MyMap@1.get(1)
> MyMap@2.get(1)
> MyMap@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()
> MyMap@1.get(1)
> MyMap@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.Nenning@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
Re: OGNL Indexed and Object Indexed Properties
Posted by foo bar <li...@gmail.com>.
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()
MyMap@1.get(1)
MyMap@2.get(1)
MyMap@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()
MyMap@1.get(1)
MyMap@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.Nenning@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
>
Antwort: OGNL Indexed and Object Indexed Properties
Posted by Christoph Nenning <Ch...@lex-com.net>.
> 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