Why do I get IllegalArgumentException Cannot convert value of type String to required type Product, in Spring?

illegalargumentexception, spring, spring-mvc

Solution

Since I can't see anything wrong with the form, the only possible reason I can imagine is that you have a parameter named `product` in the URL of your form page.

If so, you can change your URLs or use `DataBinder.setDisallowedFields()` to disable the attempt to bind that parameter.

Problem

I receive the exception Failed to convert property value of type [java.lang.String] to required type [beans.Product] for property product; nested exception is java.lang.IllegalArgumentException: Cannot convert value of type [java.lang.String] to required type [beans.Product] for property product: no matching editors or conversion strategy found in the Errors errors object even before my DetailProductValidator starts validating through the validate method. I don't understand why Spring does that. I don't have any input field that is mapped directly to the product property/object. I just use the product object's properties in the jsp. For example, I use: ``` <form:options items="${dpBackObj.product.colorMap}"/> <!-- or --> ${dpBackObj.product.priceInDollars} ``` but I never use: ``` <form:input path="product"/> ``` Can anyone please explain why this happens? And maybe inform me of a simple solution? The bean configuration for the controller is: ``` <!-- DETAIL PRODUCT FORM CONTROLLER --> <bean id="productDetailFormController" name="/detail.htm /addToCart.htm" class="detailProduct.DetailProductFormController"> <property name="sessionForm" value="true" /> <property name="commandName" value="dpBackObj" /> <property name="commandClass" value="detailProduct.DetailProductBackingObject" /> <property name="validator"> <bean class="detailProduct.DetailProductValidator" /> </property> <property name="formView" value="detail" /> <property name="successView" value="redirect:/viewCart.htm" /> <property name="cartService" ref="cartServiceImpl"/> </bean> ``` The backing object for the DetailProductFormController is: ``` public class DetailProductBackingObject { private String quantityOverflowError; private Product product; private int quantity; private ShoppingCart shoppingCart; private long sizeId; private long colorId; public DetailProductBackingObject() { this.product = new Product(); this.sizeId = -1; this.colorId = -1; } //getters and setters } ``` If you need some other info, I will provide. I am using Spring 2.5.5. Kind Regards, Despot EDIT1 (due to request from axtavt): ``` <form:form method="post" commandName="dpBackObj"> <table width="730" border="0" cellspacing="0" cellpadding="0"> <c:if test="${!empty dpBackObj.quantityOverflowError}"> <tr> <td> <c:out value="${dpBackObj.quantityOverflowError}"/> </td> </tr> </c:if> <spring:bind path="dpBackObj.*"> <c:if test="${not empty status.errorMessages}"> <div class="val-summary text-error" id="errorDivId"> <div style="" class="val-summary text-error" id="errorDivId"> <fmt:message key="detail.error.header"/> <ul> <c:forEach items="${status.errorMessages}" var="error"> <li><c:out value="${error}"/></li> </c:forEach> </ul> </div> </div> </c:if> </spring:bind> <tr> <td width="310" align="left" valign="top"> <img src="${imagesPath}/${dpBackObj.product.largeImageUrl}" alt="${dpBackObj.product.description}" /> </td> <td width="420" align="left" valign="top"> <div id="tls_detPName"> <c:out value="${dpBackObj.product.name}"></c:out> </div> <div > <strong class="numeric">${dpBackObj.product.priceInDollars}</strong> </div> <div id="tls_detPDescLong"> ${dpBackObj.product.largeDescription} <br /> </div> <div > <table cellpadding="2" border="0"> <tr> <td align="right"> <label for="p_sizes" class="label"><fmt:message key="viewCart.Size"/></label> </td> <td> <form:select path="sizeId" > <form:option value="-1" label="x"/> <form:options items="${dpBackObj.product.sizeMap}"/> </form:select> </td> </tr> <tr> <td align="right"> <label for="p_colors" class="label"><fmt:message key="viewCart.Color"/></label> </td> <td> <form:select path="colorId" > <form:option value="-1" label="y"/> <form:options items="${dpBackObj.product.colorMap}"/> </form:select> </td> </tr> </table> </div> <div id="tls_addToCart"> <div > <label for="quantityId" class="label"><fmt:message key="viewCart.Quantity"/>:</label> <form:input path="quantity" onkeypress="return checkForNumber(this, event)" maxlength="10" size="3" id="quantityId" cssClass="textbox-center"/> <input type="image" name="addToCartButtonName" src="${imagesPath}/addToCartBtn.jpg" /> </div> </div> </td> </tr> </table> </form:form> ``` EDIT2 (due to JacobM's request): This is my Validator: ``` public class DetailProductValidator implements Validator { public boolean supports(Class clazz) { return DetailProductBackingObject.class.equals(clazz); } public void validate(Object obj, Errors errors) { DetailProductBackingObject detailProductBackingObject = (DetailProductBackingObject) obj; if (detailProductBackingObject.getSizeId() == -1) { errors.rejectValue("sizeId", "error.detail.jsp.choose.size", null, "Input size."); } } } ``` When I reach the line DetailProductBackingObject detailProductBackingObject = I already have the error. The converting of the request parameters to the backing object properties happens in http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/web/servlet/mvc/BaseCommandController.html . This is what Spring says about the conversion: Populating using request parameters and PropertyEditors: Upon receiving a request, any BaseCommandController will attempt to fill the command object using the request parameters. This is done using the typical and well-known JavaBeans property notation. When a request parameter named 'firstName' exists, the framework will attempt to call setFirstName([value]) passing the value of the parameter. Nested properties are of course supported. For instance a parameter named 'address.city' will result in a getAddress().setCity([value]) call on the command class. It's important to realise that you are not limited to String arguments in your JavaBeans. Using the PropertyEditor-notion as supplied by the java.beans package, you will be able to transform Strings to Objects and the other way around. For instance setLocale(Locale loc) is perfectly possible for a request parameter named locale having a value of en, as long as you register the appropriate PropertyEditor in the Controller (see initBinder() for more information on that matter. Validators: After the controller has successfully populated the command object with parameters from the request, it will use any configured validators to validate the object. Validation results will be put in a Errors object which can be used in a View to render any input problems.

Original source