Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is Struts2 converting my string to a string array?

Tags:

java

struts2

I have a Struts 2 (JDK 1.7, Struts 2.2.1) application that contains a list of filtering criteria, stored as strings in a map.

Map< String, String > m_filters = new HashMap< String, String >();

public Map< String, String > getFilters() {
    return m_filters;
}

I pass a URL formatted like this:

http://myserver.com/myapp/GenerateReport.action?reportID=Whatever&filters.fromDate=0&filters.toDate=2000000000&filters.FcsType=piv_cardholder_3kp&detailed=true

Even though the Map has both key & value types specified as String, attempting to get a value from this

    Map< String, String > filters = getFilters();
    String value = filters.get( "fromDate" );

causes this exception to be thrown:

java.lang.ClassCastException: [Ljava.lang.String; cannot be cast to java.lang.String

I reproduced this in a unit test, and confirmed in a debugger that Struts 2 seems to be creating a String[1] instead of a String for each of the parameters. i.e. it is a length-1 string array with the only string being the expected value ("0" in this case).

My question is: Is this a bug in Struts2, or am I doing something incorrectly?

If it is a bug, is there a known workaround?

like image 608
Shawn D. Avatar asked Nov 28 '12 19:11

Shawn D.


2 Answers

There are no issues if you follow Java bean conventions.

Here are some guidelines to resolve the issue:

  • This issue does not happen if you name the private member "filter" and provide only a getter for filter.
  • This issue does not happen if you provide a public setter (even if you use a different name for the private member such as m_filter) in addition to the getter
  • this issue only happens if you do not provide a setter and the property does not have the same name as the getter.

Long story short follow conventions. Above behaviour tested with Struts 2.3.4

What I'm guessing is happening: The getter allows for setting too (If there was only a setter you could only set one item in the map, well with the current parameter interceptor this is the case). The bean is inspected for the property to see how it should do type conversion probably first it looks for a setter failing that it looks at the action for a propterty of that name to determine the type failing that it will need to use the default. The default parameter type is a mapping of String to String[] and this is what you are seeing.

like image 129
Quaternion Avatar answered Sep 22 '22 07:09

Quaternion


You're using the wrong notation. filters.fromDate would be the equivalent of getFilters().setFromDate(), which is not actually what you want. Dot notation is for JavaBeans.

Try using brackets, such as filters['fromDate'].

Refer to: http://struts.apache.org/2.2.1/docs/type-conversion.html#TypeConversion-RelationshiptoParameterNames.

like image 42
Steven Benitez Avatar answered Sep 22 '22 07:09

Steven Benitez