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="va开发者_开发知识库lidator">
<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,
DespotEDIT1 (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.
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.
精彩评论