Issue 1:
Ken Egervari opened SPR-8665 and commented

I have an application that I've recently upgraded to 3.0.6 from 3.0.5. The application used a property editor to convert a String to a List of objects, back and forth.

I am positive this code used to work. In fact, the unit tests for the property editor continue to work as expected.

However, whenever a controller uses the property editor, it wraps the List of objects with ANOTHER list, which is absolutely not what we want to happen. Did they change how property editors work? How do I fix it?

My init binder method looks like this:

@InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(List.class, new UsernamesToRecipientsEditor(userAccountDao));
}

Because java is weakly typed when it comes to List, I want you to know that this is really a List<Recipient> and not just a List of any random object. Here is the property editor code:

public class UsernamesToRecipientsEditor extends PropertyEditorSupport {
private UserAccountDao dao;
public UsernamesToRecipientsEditor(UserAccountDao dao) {
this.dao = dao;
}
@Override
public String getAsText() {
Object obj = getValue();
if(obj == null) {
return "";
}
if(obj instanceof List) {
List<Recipient> recipients = (List<Recipient>) obj;
StringBuilder builder = new StringBuilder();
for(Iterator<Recipient> iterator = recipients.iterator(); iterator.hasNext();) {
Recipient recipient = iterator.next();
builder.append(recipient.getUserAccount().getUsername());
if(iterator.hasNext()) {
builder.append(", ");
}
}
return builder.toString();
}
throw new IllegalArgumentException("Value must be a UserAccount");
}
@Override
public void setAsText(String text) {
List<Recipient> recipients = new ArrayList<Recipient>();
if(!StringUtils.hasText(text)) {
setValue(recipients);
return;
}
for(String username : StringUtils.commaDelimitedListToSet(text)) {
UserAccount userAccount = dao.findByUsername(username.trim());
if(userAccount != null) {
Recipient recipient = new Recipient(userAccount);
if(!containsRecipient(recipients, recipient)) {
recipients.add(recipient);
}
}
}
setValue(recipients);
}
private boolean containsRecipient(List<Recipient> recipients, Recipient recipient) {
for(Recipient r : recipients) {
if(r.getUserAccount().getId() == recipient.getUserAccount().getId()) return true;
}
return false;
}
}

Basically what this code does is it converts a string containing a bunch of username's separated by commas and converts them to the actual user objects, back and forth between them. It works in unit tests, and this worked in the past.

Unfortunately, after Spring MVC calls into this property editor, it wraps the result from setValue(recipients) inside of ANOTHER List... so the end result is a "List of a List of Recipients". This isn't what I want.

Since this code above USED TO work, I have to conclude that some bug or behavioral change has happened. Please help.

Affects: 3.0.6

Reference URL: http://stackoverflow.com/questions/7293928/did-spring-framework-3-0-6-break-property-editor-support-for-lists

Issue Links:

#13316 Collection Binding broken - TypeConverterDelegate does bind Collection Elements to Collection type instead of the collection elements Type ("duplicates")

Issue 2:
Marvel opened SPR-5213 and commented

I saw a similar issue raised out by Jasper Rosenberg (#8738 ).

I would like to share my understanding on this , code snippet below is using the non-thread safe variable beanClass, which may cause issue in multiple thread environment.

private Object beanClass

public String getBeanClassName() {
if (this.beanClass instanceof Class) {
return ((Class) this.beanClass).getName();
}
else {
return (String) this.beanClass;
}
}

public Class resolveBeanClass(ClassLoader classLoader) throws ClassNotFoundException {
//This may cause issue related to synchronized
if (this.beanClass == null) {
return null;
}
Class resolvedClass = ClassUtils.forName(getBeanClassName(), classLoader);
this.beanClass = resolvedClass;
return resolvedClass;
}

Please let me know if this is fixed in higher version of Spring.

Affects: 2.0.3

Attachments:

issue.bmp (8.67 kB)

Issue Links:

#9885 Class cast exception in AbstractBeanDefinition.getBeanClassName(AbstractBeanDefinition.java:305) ("is duplicated by")

Backported to: 2.0.8