registerCustomEditor to a collection of custom classes
I have a collection of a custom class (with it's own custom PropertyEditor) in my command class.
My JSP has a multi-select box. I want the values selected to be converted into a List of my custom class objects. I followed this posting:
http://forum.springframework.org/showthread.php?t=17646
Which works fine when using an array as the command property, but fails when using a collection.
My Command Class looks like this:
Code:
public class MyBackingObject {
List myClasses;
// accessors
}
My Form Controller registers the custom property editor like this:
Code:
...
binder.registerCustomEditor(
MyClass.class,
"myClasses",
new MyClassPropertyEditor());
...
According to the JavaDoc for DataBinder.registerCustomEditor:
Quote:
If the field denotes an array or Collection, the PropertyEditor will get applied either to the array/Collection itself (the PropertyEditor has to create an array or Collection value) or to each element (the PropertyEditor has to create the element type), depending on the specified required type.
I interpreted this as meaning that since the field I specified ("myClasses") is a collection, but the class I specified is not a collection "MyClass.class", then DataBinder would use the PropertyEditor to create the elements. But this is not the case. DataBinder basically ignores my customEditor because the type registered "Role.class" doesn't match the actual type "List.class". The list ends up getting populated with Strings, and I end up with a ClassCastException.
So my question is, am I interpreting the JavaDoc right?
Note: as a work around, I created a custom CustomCollectionEditor that takes an instance of a PropertyEditor which it uses to populate a collection.
Code:
public class MyCollectionPropertyEditor extends CustomCollectionEditor {
PropertyEditor propEditor;
public CollectionPropertyEditor(Class collectionType, PropertyEditor propEditor) {
super(collectionType);
this.propEditor = propEditor;
}
protected Object convertElement(Object element) {
Object returnMe = null;
if(element instanceof String) {
//not thread safe, is that a problem?
propEditor.setAsText((String)element);
returnMe = propEditor.getValue();
}
else {
returnMe = element;
}
return returnMe;
}
}
And I register like this:
Code:
...
binder.registerCustomEditor(
List.class,
"myClasses",
new MyCollectionPropertyEditor(
List.class, new MyClassPropertyEditor()));
...
Any opinions on this solution?
SELECT form elements are not implicitly treated as collectio
This is a very subtle issue that relates ultimately to the way that form data is marshalled into strings by the browser.
If you have form data whose path indicates that the value is part of a collection, it will be handled as you expect in your post. Example:
Code:
<spring:bind path="command.mycollection[3]">
<input type="text" name="${status.expression}">
</spring:bind>
The name will ultimately resolve to mycollection[3] and it's clear from this notation that the value should be inserted by a PropertyEditor into the 3rd element of the mycollection collection. Each value of the mycollection object will correspond to a single request parameterName / Value pair.
I falsely believed that multiple-select form input elements would be handled by the DataBinder similarly, as you did. Keep in mind that this kind of form input element:
Code:
<spring:bind path="command.mycollection">
<select name="${status.expression}">
....
</select>
</spring:bind>
Will result in only one parameter being passed back to the server: a CSV list of the selected elements. It will be a single parameter name / value pair, and as a GET parameter it would look like this:
Code:
http://foo.com?mycollection=22,234,42,2,234,11,232
There is no way to register a CustomPropertyEditor that will operate on each of the elements implicitly, as someone must first unmarshall that CSV string into individual values.
You can of course register an editor that accepts a string of CSV values as input, unmarshalls the values, and then operates on each value individually. You can find various solutions around this forum that do exactly that.
You would likely register such an editor like so:
Code:
registerCustomEditor(Set.class, "myImplicitCollection", new CustomUnMarshallingMojoCollectionEditor());