Announcement Announcement Module
Collapse
No announcement yet.
Conversion strategy for list of specific object as property Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Conversion strategy for list of specific object as property

    (sorry if the following question is in the wrong forum: it seems web oriented but I think the problem is specific to the conversion mechanisms)

    I have the following form:

    Code:
    <form:form commandName="entry" method="POST">
      <form:input type="text" path="name"/>
      <form:input type="text" path="tags" />
      <input type="submit" value="Submit"/>
    </form:form>
    Which is going to be bind to the following JavaBean:

    Code:
    public class Entry {
      private String name;
      private List<Tag> tags = new LinkedList<Tag>();
    
      // setters and getters omitted
    }
    Because I want to take use all new fancy features of Spring 3, I'm using annotation-driven controller to receive the POST request:

    Code:
    @Controller
    @RequestMapping("/entry")
    public class EntryController {
    
      @RequestMapping(method = RequestMethod.GET)
      public ModelAndView show() {
        ModelAndView mav = new ModelAndView("entry");
        mav.addObject(new Entry());
        return mav;
      }
    
      @RequestMapping(method = RequestMethod.POST)
      public String add(@ModelAttribute("entry") @Valid Entry entry, 
                        BindingResult result) {
        // check validation from Binding result
        // execute method on business beans: adding this entry to the system
        // return a view if correct
      }
    }
    As you can see, I need to convert my input text (which look like "tag1, tag2, tag3") as a list of Tag, this last object defines like this:

    Code:
    public class Tag {
      private String name;
    
      // setter and getter omitted
    }
    Spring 3.0 has several conversion mechanisms.

    1. The simplest way

    Programming a new property tagsAsText to have a getter/setter as String:

    Code:
    public class Entry {
      // ...
    
      public void setTagsAsText(String tags) {
        // convert the text as a list of tags 
      }
    
      public String getTagsAsText() {
        // convert list of tags to a text
      }
    }
    This approach has one drawback: I include the conversion logic in my domain object. So my first question is: "is this a problem ?"

    2. The Property Editor way

    I can also use a BeanInfo for my bean:

    Code:
    public class EntryBeanInfo extends SimpleBeanInfo {
    
      public PropertyDescriptor[] getPropertyDescriptors() {
        try {
          @Override
          PropertyDescriptor tagsDescriptor = new PropertyDescriptor("tags", Entry.class) {
            @Override  
            public PropertyEditor createPropertyEditor(Object bean) {
                    return new EntryTagListEditor(Integer.class, true);
                };
            };
            // omitting others PropertyDescriptor for this object (for instance name)
            return new PropertyDescriptor[] { tagListDescriptor };
        }
        catch (IntrospectionException ex) {
            throw new Error(ex.toString());
        }
      }
    }
    And declares one PropertyEditor:

    Code:
    public class EntryTagListEditor extends PropertyEditorSupport {
    
      public void setAsText(String text) {
        // convert the text to a list of Tag
      }
    
      public String getAsText() {
        // convert the list of Tag to a String
      }
    }
    This approach has another drawback: I need to edit my BeanInfo every time I add / change property of my Entry class. So my second question: is there any way to have a simple way to define my BeanInfo (like "for this property, use this, else just do as usual") ?

    3. The Converter way

    Converter uses the generic mechanism of Java 5, and it seems more elegant. I just have to define the following converter (and eventually the opposite one: converting TagList to String):

    Code:
    final class StringToTagList implements Converter<String, List<Tag>> {
      public List<Tag> convert(String source) {
        // convert my source to a list of Tag
      }
    }
    Then i register a new Conversion Service:

    Code:
        <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
            <property name="converters">
                <list>
                    <bean class="fr.unilim.msi.stages.converters.StringToTagListConverter" />
                    <bean class="fr.unilim.msi.stages.converters.TagListToStringConverter" />
                </list>
            </property>
        </bean>
    With declaring the bean to use it with MVC:

    Code:
        <mvc:annotation-driven conversion-service="conversionService"/>
    But the system seems to use this conversionService for every conversion, so I've exception during startup when converting a database driver name in a property file:

    Caused by: org.springframework.core.convert.ConversionFailedE xception: Unable to convert value "org.h2.Driver" from type 'java.lang.String' to type 'java.lang.String'; nested exception is java.lang.UnsupportedOperationException: Not supported yet.

    Note: the UnsupportedOperationException comes from my code, I didn't implement the convert code.

    So my third question: What is the problem ? How can I keep the default conversion classes in my application when adding mine ?

    Notes

    It seems other possibilities are available: I found a class StringArrayPropertyEditor which can convert a String as CSV separated by comma to an array of String, but I want to change the property "name" of my object tag, and I want to keep the list and not use an array.

    So my last question: What is the best way ?

    PS: sorry for this long question.
Working...
X