According to the OGNL spec, setting indexed JavaBean properties using lijst[0], lijst[1] etc should work. And it does; except not through struts 2's params interceptor. Try it out:

public class ActionTest extends ActionSupport {
private List<String> someProperty = new ArrayList<String>(); public ActionTest(){ try {
           Ognl.setValue("someProperty[0]", this, "Foo");
       }
       catch(Exception ex){
           ex.printStackTrace();
       }
} public String execute(){
       return SUCCESS;
   }
public String getSomeProperty(int index){
       return someProperty.get(index);
   }
public void setSomeProperty(int index, String name){
       someProperty.set(index, name);
   }
}

Set a breakpoint on setSomeProperty and you will find that it calls the indexed setter exactly as it should. I've been debugging this around a bit to see why this doesn't work through the Struts 2 params interceptor, and I found that apparently this is due to the fact that Struts does not pass the action instance itself as the object to evaluate the OGNL expression against, but rather a CompoundRoot of the action and a DefaultTextProvider.

When the OGNL expression "someProperty[0]" is evaluated, OGNL will parse the expression into an ASTChain of 2 ASTProperty's. ASTChain.setValueBody is then called to execute the appropriate setter. What's preventing the indexed setter from being executed is propertyNode.getIndexedPropertyType(context, target) returning the wrong index type.

The index type of a property (see ASTProperty.getIndexedPropertyType) appears to be ultimately determined in OgnlRuntime.getIndexedPropertyType, which fetches a PropertyDescriptor for the specified object's class and property (ie. "someProperty" in this case). The problem here is that, since the object is a CompoundRoot, a property descriptor for CompoundRoot.class is returned, which understandably has no property descriptor for "someProperty" since it has no indexed setter for "someProperty", causing it to return INDEXED_PROPERTY_NONE (ie. not indexed) instead of INDEXED_PROPERTY_OBJECT. When the action instance itself is passed as the object to evaluate against, a property descriptor is fetched for the actual action class (ActionTest.class), and an ObjectIndexedPropertyDescriptor is returned for "someProperty" as expected.

So it looks like the root cause is that only the methods of CompoundRoot are considered for determining any indexed setters, not those of the objects it contains. I'm sure there are a whole slew of a problems abound if you would propagate the lookup into the contained objects, and even if you did, the property descriptors are only assigned once and then reused, so you'd still only get the descriptors for the first CompoundRoot object you encounter.

I'm fairly new to the Struts 2 and OGNL codebase and I'm not sure what the best way to fix it would be, but I hope this might provide some insight or even serve as a rough bug report.

newton.dave wrote:
Timmos wrote:
Hi,

I figured out how to generate a form with dynamic length. The submitting
part remains a bit tricky, but before you redirect me to OGNL / Type
Conversion pages, I have to say I already read those articles.

This is a part of my generated .jsp (the generate part - I won't include
the
Action code for this):

<s:iterator value="properties" status="stat">
    <s:textfield name="lijst[2]" label="%{name}" />
</s:iterator>

As you can see, for testing purposes I hard-coded the index "2", but I
don't
know if this syntax is correct.

This form is to be submitted to DoSearchAction:

public void setLijst(int index, String s) {
     lijst[index] = s;
     System.out.println(">>>> LIJST!!! >> " + index + ":::" + s);
}

When I run this piece of junk, I get: ognl.OgnlException: target is null
for
setProperty(null, "2", [Ljava.lang.String;@13dd8).

I would like to know what is wrong with the setter / s:textfield name
parameter. What do I have to do to get it working?
(1) If there are multiple parameters w/ the same name the framework appears to put them into a collection: it may not be necessary to do *anything*.

(2) IIRC using indexed setters would use the (n) syntax (not [n]), but I could be remembering wrong. In any case, you don't need to use an indexed setter, just have an appropriate collection property with a setter, say:

private List<String> lijst;
public void setLijst(List l) { lijst = l; }

(Or whatever.)

Dave


---------------------------------------------------------------------
To unsubscribe, e-mail: user-unsubscr...@struts.apache.org
For additional commands, e-mail: user-h...@struts.apache.org



Thx. What should the name attributes of my textfield be then, knowing that
"lijst" is my List to set?

<s:textfield value="" name"lijst" /> ? And it should work?

Reply via email to