Using: Spring 3.2 portlet MVC with Liferay 5.2.3 and Tomcat 6.0.18
I'm trying to create a PropertyEditor to convert between Set<Type>
and String
, and back again. I have successfully got Set<Type>
to String
to work without problems. But I can't get property editor to be recognized for the reverse direction. I've done this successfully with Type
-> String
-> Type
, but doing the conversion for a Set
is eluding me.
I have determined that the SetAsText method is never invoked, and I get a runtime error that shows that the conversion wasn't done. Information about propertyEditors is very sparse, and with one or two exceptions the only vaguely related issues I could find are 4 or more years old.
Either I'm missing something so fundamental that I can't see it, or it's something deeper in the framework, but I would be grateful for any help or suggestions.
Here's the @InitBinder snippet from my controller:
@InitBinder("formBacking")
public void initBinder(WebDataBinder binder){
binder.registerCustomEditor(Set.class, "field", new SetEditor(listService, Set.class));
logger.info("FormBacking Binder initialization");
}
Here's my PropertyEditor:
public class SetEditor extends PropertyEditorSupport {
protected static Logger logger = Logger.getLogger("PropertyEditor");
private ListService listService;
public SetEditor(ListService listService, Class clazz) {
super(clazz);
this.listService = listService;
}
@Override
public String getAsText() {
Stack<String> returnString = new Stack<String>();
Set<Type> types = new HashSet<Type>();
try {
types = (Set<Type>)this.getValue();
for (Type type:types) {
returnString.push(type.getTypeId().toString());
}
} catch (NullPointerException e) {
logger.info("getAsText is \"\"");
return "";
} catch (Exception e) {
logger.info("getAsText Other Exception: " + e.getMessage());
return "";
}
return "[" + StringUtils.collectionToDelimitedString(returnString,",") + "]"; // a very useful Spring Util
}
@Override
public void setAsText(String text) throws IllegalArgumentException {
Type type = new Type();
Set<Type> result = new HashSet<Type>();
try {
String[] typeArray = text.split("[,]"); //this may not be correct, but I can't get here to debug it!!
for(String type:typeArray) {
if(!type.isEmpty()) {
type = listService.getType(Long.valueOf(text));
result.add(type);
}
}
}catch(NullPointerException e) {
logger.info("SetAsText is \"\" ");
setValue(null);
}
catch(Exception e) {
logger.info("setAsText Other Exception: " + e.getMessage());
}
setValue(result);
}
}
the Type class snippet is:
@Entity(name="Type")
@Table(name="type")
public class Type {
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name = "playListImages",
joinColumns={@JoinColumn(name="superTypeId")},
inverseJoinColumns={@JoinColumn(name="typeId")})
private Set<Type> types = new HashSet<Type>();
getters and setters...
Hopefully this will help any one else who has struggled to resolve this issue.
After a bit of further investigation (i.e. turning on Trace logging), it appears that Spring Annotations doesn't fully register
PropertyEditors
that are associated withSet
(maybeCollections
in general, although I haven't verified that). Trace showed the built-inCustomCollectionEditor
being invoked (but only onString
->Type
conversions), even though I had registered my own editor.This, imho, is a Spring Annotations bug. The work around, which fully works as I expected, is to create your own property editor registrar and register the property editor in the xxx-portlet.xml configuration file.
For example: project-portlet.xml should include something along these lines:
Registration class: