Hi everyone,
I am doing a new web project, and still using the old property editor in spring 2.5. Recently I met a strange problem: a form Select tag has multiple values selected while it is not supposed to, and the same similar tags work fine in other places.
Please see my code snippets below:
Code:public class MyBindingInitializer implements WebBindingInitializer { @Autowired private MiscService miscService; public void initBinder(WebDataBinder binder, WebRequest request) { binder.registerCustomEditor(byte[].class, new ByteArrayMultipartFileEditor()); SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy"); dateFormat.setLenient(false); binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true)); binder.registerCustomEditor(BigDecimal.class, new BigDecimalEditor()); binder.registerCustomEditor(String.class, new StringEditor()); binder.registerCustomEditor(Category.class, new CategoryPropertyEditor(miscService)); binder.registerCustomEditor(Supplier.class, new SupplierPropertyEditor(miscService)); binder.registerCustomEditor(Color.class, new ColorPropertyEditor(miscService)); binder.registerCustomEditor(Size.class, new SizePropertyEditor(miscService)); } }Code:@Entity @Table(name="size_def", uniqueConstraints=@UniqueConstraint(columnNames={"name"})) public class Size extends BaseObject { private static final long serialVersionUID = 1L; private Long id; private String name = ""; private String systemCode = ""; private Integer seqNo; private Integer version; @Id @GeneratedValue(strategy = GenerationType.AUTO) public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Column(name="sys_code") public String getSystemCode() { return systemCode; } public void setSystemCode(String systemCode) { this.systemCode = systemCode; } @Column(name="seqno") public Integer getSeqNo() { return seqNo; } public void setSeqNo(Integer seqNo) { this.seqNo = seqNo; } @Version public Integer getVersion() { return version; } public void setVersion(Integer version) { this.version = version; } @Override public boolean equals(Object o) { boolean equals = false; if (o!= null && Size.class.isAssignableFrom(o.getClass()) ) { Size c = (Size) o; equals = (new EqualsBuilder() .append(getName(), c.getName())) .isEquals( ); } return equals; } @Override public int hashCode() { return (getName() != null ? getName().hashCode() : 0); } @Override public String toString() { return new ToStringBuilder(this, ToStringStyle.SIMPLE_STYLE).append(getName()).toString(); } }Code:public class SizePropertyEditor extends PropertyEditorSupport { private MiscService miscService; public SizePropertyEditor(MiscService miscService) { this.miscService = miscService; } public void setAsText(String text) throws IllegalArgumentException { if(StringUtils.isBlank(text)){ setValue(null); } else{ Long id = Long.parseLong(text); Size s = (Size)miscService.get(Size.class, id); setValue(s); } } public String getAsText() { Object value = getValue(); if(value==null) return ""; Size s = (Size)value; return ""+s.getId(); } }
Code:@Controller @SessionAttributes("productVariant") public class ProductVariantFormController extends BaseController { @RequestMapping(method=RequestMethod.GET, params="method=edit") public void edit(@RequestParam("id") Long id, ModelMap model){ ProductVariant productVariant = (ProductVariant) miscService.get(ProductVariant.class, id); model.addAttribute(productVariant); } @RequestMapping(method=RequestMethod.GET, params="method=add") public void add(@RequestParam("prodId") Long prodId, ModelMap model){ ProductEntity pe = (ProductEntity)miscService.get(ProductEntity.class, prodId); ProductVariant productVariant = new ProductVariant(); productVariant.setProductEntity(pe); model.addAttribute(productVariant); } @RequestMapping(method=RequestMethod.POST) public String processSubmit(HttpServletRequest request, @ModelAttribute("productVariant") ProductVariant productVariant, BindingResult result, SessionStatus status){ ProductVariantValidator productVariantValidator = new ProductVariantValidator(miscService); productVariantValidator.validate(productVariant, result); if(result.hasErrors()){ translateErrors(result, request); return "/catalog/productVariantForm"; } productVariant = (ProductVariant) miscService.save(productVariant); saveFormMessage(request, messageSource.getMessage("changes.saved", null, request.getLocale())); status.setComplete(); return "redirect:/catalog/productVariantForm.html?method=edit&id=" + productVariant.getId(); } @SuppressWarnings("unchecked") @ModelAttribute("colorList") public List<Color> getAllColors(){ List<Color> colorList = miscService.getAll(Color.class); Collections.sort(colorList, new GenericComparator("name")); return colorList; } @SuppressWarnings("unchecked") @ModelAttribute("sizeList") public List<Size> getAllSizes(){ List<Size> sizeList = miscService.getAll(Size.class); Collections.sort(sizeList, new GenericComparator("seqNo")); return sizeList; } }The strange thing is, the color select tag works totally fine with similar setting (background list and property editor), while the size select tag has got two values selected (id=1 or id=5), while only the first one is correct. I've also checked the size object fields, and it's correct.Code:<form:form modelAttribute="productVariant" cssStyle="width: 100%;"> <%@ include file="/common/formMessages.jsp" %> <table class="borderless"> <tr> <td> Product </td> <td> ${productVariant.productEntity.name} </td> </tr> <tr> <td> SKU<span class="required">*</span> </td> <td> <form:input path="sku" size="80" maxlength="128"></form:input> </td> </tr> <tr> <td> Color </td> <td> <form:select path="color"> <form:option value="" label="Select"/> <form:options items="${colorList}" itemValue="id" itemLabel="name"/> </form:select> </td> </tr> <tr> <td> Size </td> <td> <form:select path="size"> <form:option value="" label="Select"/> <form:options items="${sizeList}" itemValue="id" itemLabel="name"/> </form:select> </td> </tr> ... <tr> <td></td> <td> <form:hidden path="version" /> <a class="button" href="#" onclick="$('#productVariant').submit(); return false;"> <span><fmt:message key="button.save"/></span> </a> <a class="button" href="<c:url value='/catalog/productEntityForm.html'/>?method=edit&id=${productVariant.productEntity.id}"> <span><fmt:message key="button.cancel"/></span> </a> </td> </tr> </table> </form:form>
Could anyone have a hint of what might be wrong?
By the way, after I replace the form:option tags with old fashioned codes below, it works fine:
But I am not happy with it, as this is verbose, and it's supposed to be done by the form:options tags.Code:<form:select path="size"> <c:choose> <c:when test="${productVariant.size==null}"> <option selected="true" value="">Select</option> </c:when> <c:otherwise> <option value="">Select</option> </c:otherwise> </c:choose> <c:forEach var="s" items="${sizeList}"> <c:choose> <c:when test="${productVariant.size.id eq s.id}"> <option selected="true" value="${s.id}">${s.name}</option> </c:when> <c:otherwise> <option value="${s.id}">${s.name}</option> </c:otherwise> </c:choose> </c:forEach> </form:select>
Thanks for help in advance.
Mark


Reply With Quote