Im trying to bind a list of 5 optional checkboxes (so 0 to 5 values will be form submitted). I want these to bind into a model field of type List<MyEnumeration>, similar to what the Amenities do on the Booking application.
I have encountered a few problems while working on this, but firstly I dont think the Booking example works quite right.
Booking.java
bookingForm.jspCode:public void setAmenities(final List<Amenity> amenities) { this.amenities = amenities; }
Rendered bookingForm.jspCode:<li><form:checkbox path="amenities" value="OCEAN_VIEW" label="Ocean View" /></li> <li><form:checkbox path="amenities" value="LATE_CHECKOUT" label="Late Checkout" /></li> <li><form:checkbox path="amenities" value="MINIBAR" label="Minibar" /></li>
If you run a debugger on it, it looks like it takes the "amenities" parameter from the request as a String (if one is selected) or Array of Strings (if more than one are selected) and converts them to a List<String>. It then puts the List into setAmenities(List<Amenity>). The JVM doesnt complain because its all done in the EL with reflection and its apparently not clever enough to figure out that the type of List is wrong. (Im told this is due to Java Generics using type Erasure) If you do something like the following in the setter, you get a ClassCastException (String to Amenity) that results in an ExpressionEvaluationException in the EL:Code:<ul> <li> <input id="amenities1" name="amenities" type="checkbox" value="OCEAN_VIEW"/> <label for="amenities1">Ocean View</label> <input type="hidden" name="_amenities" value="on"/> </li> <li> <input id="amenities2" name="amenities" type="checkbox" value="LATE_CHECKOUT"/> <label for="amenities2">Late Checkout</label> <input type="hidden" name="_amenities" value="on"/> </li> <li> <input id="amenities3" name="amenities" type="checkbox" value="MINIBAR"/> <label for="amenities3">Minibar</label> <input type="hidden" name="_amenities" value="on"/> </li> </ul>
Booking.java
I dont think theres any place in the sample app where the Amenities are extracted from a saved Booking, but if they were, I think ClassCastExceptions would ensue.Code:public void setAmenities(final List<Amenity> amenities) { this.amenities = amenities; for(Amenity a : this.amenities){ //ClassCastException thrown System.out.println("Amenity: "+ a); } }
So, part 2, Id like to sidestep this by doing custom conversion. The problem I have there is that when one box is selected it wants to convert String to List, but when 2 or more are selected, it wants to convert Array of String to List. However I can only associate one custom converter Id with the bound field:
webflow code
Converter Code:Code:<binder> <binding property="amenities" required="false" converter="myAmenitiesConverter"/> </binder>
I tried using indexed properties to force the source type to be an array all the time, but webflow didnt seem to work with that:Code:public Class getSourceClass() { return String[].class; //or return String.class; ??? } public Class getTargetClass() { return List.class; }
Any help on what to do about mapping checkboxes into Lists of Enums is greatly appreciated but hopefully someone will at least check out the Booking example and confirm or disconfirm that its got a problem.Code:<li><form:checkbox path="amenities[0]" value="X" label="X" /></li> <li><form:checkbox path="amenities[1]" value="Y" label="Y" /></li>


Reply With Quote

