PropertyEditor issue with Set type

1.3k views Asked by At

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...
1

There are 1 answers

0
pjl55 On

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 with Set (maybe Collections in general, although I haven't verified that). Trace showed the built-in CustomCollectionEditor being invoked (but only on String -> 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:

    <bean class="org.springframework.web.portlet.mvc.annotation.AnnotationMethodHandlerAdapter">
       <property name="webBindingInitializer">
          <bean class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
             <property name="propertyEditorRegistrars">
                <list>
                   <ref bean="myPropertyEditorRegistrar" />
                </list>
             </property>
         </bean>
      </property>
   </bean>

<bean id="myPropertyEditorRegistrar"
class="com.sbeko.slider.util.MyPropertyEditorRegistrar" />

Registration class:

public class MyPropertyEditorRegistrar implements PropertyEditorRegistrar {

   public void registerCustomEditors(PropertyEditorRegistry registry) 
             {registry.registerCustomEditor(Set.class, new TypeEditor(Set.class));
}