I get an exception
Failed to convert property value type [java.lang.String] into the required type [beans.Product] for the product property; nested exception java.lang.IllegalArgumentException: Cannot convert value of type [java.lang.String] for required type [beans.Product] for product properties: no matching editors or conversions found strategy
in the error error object even before my DetailProductValidator starts validation using the validation method.
I do not understand why Spring does this. I do not have an input field that maps directly to a product property / object. I just use product object properties in jsp. For example, I use:
<form:options items="${dpBackObj.product.colorMap}"/> ${dpBackObj.product.priceInDollars}
but i never use:
<form:input path="product"/>
Can someone explain why this is happening? And maybe let me know about a simple solution?
Controller bean configuration:
<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>
Support object for DetailProductFormController element:
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; }
If you need any other information, I will provide. I am using Spring 2.5.5.
Yours faithfully,
Despot
EDIT1 (due to a 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 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 get to the line DetailProductBackingObject detailProductBackingObject = I already have an error.
The conversion of query parameters to properties of the base object occurs at http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/web/servlet/mvc/BaseCommandController.html . This is what Spring says about conversion:
Filling using the request parameters and PropertyEditors: after receiving the request, any BaseCommandController will try to execute the object command using the request parameters. This is done using the typical and well-known property of JavaBeans notation. When the request parameter name 'firstName' exists, it will try to call setFirstName ([value]), which passes the value of the parameter. Nested properties are of course supported. For example, a parameter named 'address.city' will result in getAddress (). setCity ([value]) calls the class of commands.
It is important to realize that you are not limited to String arguments in your JavaBeans. Using the PropertyEditor concept provided by the java.beans package, you will be able to convert strings to objects and vice versa. For example, setLocale (Locale loc) is perfectly possible for a query parameter named locale that has the value en, for how long when you register the corresponding PropertyEditor in the controller (see initBinder () for more information about this.
Validators: after the controller has successfully completed the object command with the parameters from the request, it will use any configured validators to validate the object. The test results will be placed in the Error Object, which can be used in the View to eliminate any input problems.