struts-user mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Christoph Nenning <Christoph.Nenn...@lex-com.net>
Subject Re: OGNL Indexed and Object Indexed Properties
Date Tue, 20 May 2014 11:26:04 GMT
> 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

Mime
  • Unnamed multipart/alternative (inline, None, 0 bytes)
View raw message