2

I'm using the Struts 2 framework and I want to transfer a list of objects from Java to JSP and back to Java. Transferring to JSP works fine with the <s:iterator> tag. Transferring back to Java does not, my list is never populated.

I already checked these questions:

and followed their suggestions.

Here is my "item" class (it is has more properties than just name, but I'm only showing relevant ones):

Class Item:

    private String name;

    public Item(){}

    public String getName(){ ... };
    public void setName(String newName){ ... };

and on my JSP I have:

<s:iterator value="items" status="key">
    <s:hidden name="items[%{#key.index}].name" value="%{name}" />
</s:iterator>

Here's the relevant part of the action class:

private  List<Item> items = new ArrayList<Item>();

public List<Item> getItems()
{
    System.out.println("now getting Items");
    
    if(Items == null)
    {
        System.out.println("Items is null");
    }
    else
    {
        System.out.println("Items is not null. size: " + Items.size());
    }
    
    return Items;
}

public void setItems(List<Item> Items)
{
    System.out.println("now setting Items");

    Items = Items;
}

I'm 100% sure it has all the necessary getters and setters because the JSP is populated correctly, and when I submit my form I can actually see (with log statements) that my getItems() method is being called once for each item in my list (for each input field in the form). It's just weird that Struts2 is getting the list once for every hidden input field in the form, but then refuses to create an Item object and set it's name to the given value anything in it. The problem cannot be the lack of a no-args constructor.

I also added an conversion file named with ActionName-conversion.properties (where ActionName is the name of my action class) and it is in the same folder as my ActionName.java class.

Element_items = Item
CreateIfNull_items = true

What might be wrong?

Roman C
  • 49,761
  • 33
  • 66
  • 176
user1884155
  • 3,616
  • 4
  • 55
  • 108
  • Your code is fine, you cleared also my first thought (`The problem cannot be the lack of a no-args constructor`). What is left ? Interceptor Stack. Please show it, I bet a beer the problem is there – Andrea Ligios Feb 27 '14 at 12:43
  • I use the default stack (which has the param interceptor). I just tested to see if I could get a list populated from my JSP (rather than a List) and this works fine. I really think there is something wrong with struts2 trying to create a new Item (or somehow not knowing the list is of type Item and thus not knowing it has to create an Item Object?). – user1884155 Feb 27 '14 at 12:46
  • 1
    Try removing your ActionName-conversion.properties (not needed here), if it doesn't work, please post just the declaration and initialization of your List in your Action class. – Andrea Ligios Feb 27 '14 at 12:54
  • Removing the properties file did not change anything. I added the relevant parts in the action class (making, getting and setting the item list) in my question. you'll see the get method has system.outs. I actually these print statements in my console 4 times, and my item list has 4 values. Item list is not null. But the amount of elements in the list always stays 0. It is not a readonly list or something similar. – user1884155 Feb 27 '14 at 13:01
  • I guess `Items` is always `items`, isn't it ? – Andrea Ligios Feb 27 '14 at 13:03
  • Yes, copy/paste issue with the capital i, sorry. Hold on. It suddenly worked. I guess removing the properties file DID work. I guess my tomcat server wasn't cleaned or something? Ok so, what did that file broke that is being fixed if the file is not there? – user1884155 Feb 27 '14 at 13:08

1 Answers1

0

If you are using List or Map for your collection of items you can reference its elements by index without using an ObjectTypeDeterminer. See

Built in Type Conversion Support

Type Conversion is implemented by XWork.

XWork will automatically handle the most common type conversion for you. This includes support for converting to and from Strings for each of the following:

  • String
  • boolean / Boolean
  • char / Character
  • int / Integer, float / Float, long / Long, double / Double
  • dates - uses the SHORT format for the Locale associated with the current request
  • arrays - assuming the individual strings can be coverted to the individual items
  • collections - if not object type can be determined, it is assumed to be a String and a new ArrayList is created

Note that with arrays the type conversion will defer to the type of the array elements and try to convert each item individually. As with any other type conversion, if the conversion can't be performed the standard type conversion error reporting is used to indicate a problem occurred while processing the type conversion.

  • Enumerations
  • BigDecimal and BigInteger

If you want to use advanced type conversion using ObjectTypeDeterminer to determine a type of object being instantiated when populated a collection or the object that is retrieved from the collection by the key property of the element in OGNL expression you should see

Collection and Map Support

Collection and Map support provides intelligent null handling and type conversion for Java Collections.

The framework supports ways to discover the object type for elements in a collection. The discover is made via an ObjectTypeDeterminer. A default implementation is provided with the framework. The Javadocs explain how Map and Collection support is discovered in the DefaultObjectTypeDeterminer.

This ObjectTypeDeterminer looks at the Class-conversion.properties for entries that indicated what objects are contained within Maps and Collections. For Collections, such as Lists, the element is specified using the pattern Element_xxx, where xxx is the field name of the collection property in your action or object. For Maps, both the key and the value may be specified by using the pattern Key_xxx and Element_xxx, respectively.

From WebWork 2.1.x, the Collection_xxx format is still supported and honored, although it is deprecated and will be removed eventually.

Additionally, you can create your own custom ObjectTypeDeterminer by implementing the ObjectTypeDeterminer interface. There is also an optional ObjectTypeDeterminer that utilizes Java 5 generics. See the Annotations page for more information.


You can use ActionClass-conversion.properties and specify all properties necessary for the type conversion. If you didn't specify some properties the defaults are applied.

In your case you didn't specify a key property, i.e. KeyProperty_items, in this case the id property of the Item is used. If you don't have such property the conversion might fail.

There's also possible to use annotations for type conversion. See examples

Also note to use correct syntax for field names using OGNL expression, which uses indexing by object reference, rather than referencing by collection index. This kind of indexing perfectly works for lists. It also works using advanced type conversion.

Why it's working is out of the topic of this question. Sure you can fix your properties and use advanced type conversion, or remove it and use indexed collection like a list.

Roman C
  • 49,761
  • 33
  • 66
  • 176