PDA

View Full Version : Help writing PropertyEditor for Pojo property in Command



Reikje
Jul 15th, 2008, 03:31 PM
I am stuck with the following scenario. I have a command bean like this:


public class Cart {
private Payment _paymentSelection;

public Payment getPaymentSelection() {
return _paymentSelection;
}

public void setPaymentSelection(Payment paymentSelection) {
Payment val = paymentSelection;
_paymentSelection = val;
}

// more properties
}

and this Payment class:



public class Payment {
private Integer _contentId;
private String _title;
private Long _price;

// getter and setter
}


I am trying to display a form where the user can edit different Cart instances. The Controller is build using Spring 2.5 annotations.


@Controller
@RequestMapping("/edit.do")
@SessionAttributes("cart")
public class CartEditController
{
@InitBinder
public void initBinder(WebDataBinder binder)
{
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
dateFormat.setLenient(false);
binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false));
}

@ModelAttribute("cart")
@RequestMapping(method = RequestMethod.GET)
public Cart getCartSearch(@RequestParam("cartId") long id)
{
Cart cart = // load the cart by the given id
return cart;
}

@ModelAttribute("payments")
public List<Payment> getPayments()
{
List<Payment> availablePayments = new ArrayList<Payment>();
// populate the list
return payments;
}

@RequestMapping(method = RequestMethod.POST)
public String processSubmit(@ModelAttribute("cart") Cart cart, BindingResult result, SessionStatus status)
{
new CartValidator().validate(cart, result);

if (!result.hasErrors())
{
// update Cart
}
return "edit";
}
}

In my view, I would like to display the list of available Payment options to the user. On submit, the right Payment instance (from the List) should be used when binding the Cart command bean. Here is my view:


<form:form commandName="cart" method="POST" action="edit.do">
<form:select path="paymentSelection" id="contentId">
<form:options items="${payments}" itemValue="contentId" itemLabel="title"/>
</form:select>
</form:form>

So far so good. When I submit the form, I get this error:


Failed to convert property value of type [java.lang.String] to required type [com.mini.biz.entities.cart.Payment] for property 'paymentSelection'; nested exception is java.lang.IllegalArgumentException: Cannot convert value of type [java.lang.String] to required type [com.mini.biz.entities.cart.Payment] for property 'paymentSelection': no matching editors or conversion strategy found

I guess I have to write a custom PropertyEditor for the @InitBinder method. How would such a PropertyEditor look like or could be done differently?

Reikje
Jul 16th, 2008, 04:29 AM
Found out myself. I had to add some sort of "toString" method, which contains all information to assemble a new Payment objects.



public String getIdentifier()
{
String contentId = _contentId == null ? "" : _contentId.toString();
String title = _title == null ? "" : _title;
String price = _price == null ? "" : _price.toString();
return contentId + ":" + title + ":" + price;
}


Then I created and registered this PropertyEditor in the @InitBinder annotated method:


PropertyEditor paymentPropertyEditor = new PropertyEditorSupport()
{
public String getAsText()
{
Payment payment = (Payment) getValue();
return payment != null ? payment.getIdentifier() : "";
}

public void setAsText(String s) throws IllegalArgumentException
{
if (!StringUtils.isBlank(s))
{
Payment payment = new Payment();
String[] tokens = StringUtils.split(s, ':');
if (tokens.length > 0)
{
payment.setContentId(Integer.parseInt(tokens[0]));
}
if (tokens.length > 1)
{
payment.setTitle(tokens[1]);
}
if (tokens.length > 2)
{
payment.setPrice(Long.parseLong(tokens[2]));
}
setValue(payment);
}
}
};
binder.registerCustomEditor(Payment.class, paymentPropertyEditor);


The last piece was to change the JSTL stuff in the View, to use "identifier" now in the itemValue property of the form:options



<form:select path="paymentSelection" id="contentId">
<form:options items="${payments}" itemValue="identifier" itemLabel="title"/>
</form:select>


Works like a charm.