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;
	}
	
}
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>
			&nbsp;
			<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>
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.

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:

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>
But I am not happy with it, as this is verbose, and it's supposed to be done by the form:options tags.

Thanks for help in advance.

Mark