2010-06-22 5 views
5

tengo la forma siguiente (simplificado) en uno de mi punto de vista:¿Cuáles son las mejores estrategias de conversión de primavera en el caso de una Cadena para convertir a un conjunto de objetos?

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

que va a ser unen a la siguiente JavaBean:

public class Entry { 
    private String name; 
    private List<Tag> tags = new LinkedList<Tag>(); 

    // setters and getters omitted 
} 

porque quiero tomar el uso totalmente nuevo de lujo características de la primavera 3, que estoy usando el controlador de anotación impulsada para recibir la solicitud POST:

@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 
    } 
} 

Como se puede ver, necesito para convertir mi texto de entrada (que loo k como tag1, tag2, tag3) como una lista de etiquetas, definen así:

public class Tag { 
    private String name; 

    // setter and getter omitted 
} 

Hay varias estrategias para hacer esto con Spring 3.0:

( puesto mucho este momento, las preguntas están en negrita)

El más simple

Programación de una nueva propiedad tagsAsText tener un captador/definidor como cadena:

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 
    } 
} 

Este enfoque tiene dos inconvenientes:

  • que incluyen la lógica de conversión en mi objeto de dominio, ¿es un problema?
  • ¿Dónde puedo acceder al BindingResult en caso de error en la cadena?

El uso de BeanInfo

También puedo utilizar un BeanInfo para mi café en grano:

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()); 
    } 
    } 
} 

Y declarar un convertidor

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 
    } 
} 

Este enfoque tiene también dos inconvenientes:

  • Necesito editar mi BeanInfo cada vez que agrego/cambio mi clase de entrada. o ¿hay alguna manera de tener una forma sencilla de definir mi BeanInfo (como "de esta propiedad, utilice esto, los demás sólo hacer como de costumbre")
  • Dónde puedo acceder a la BindingResult en el caso de error en la cuerda?

El uso de convertidor

convertidor utiliza el mecanismo genérico de Java 5:

final class StringToTagList implements Converter<String, List<Tag>> { 
    public List<Tag> convert(String source) { 
    // convert my source to a list of Tag 
    } 
} 

Este enfoque parece más elegante, pero todavía dos inconvenientes:

  • Parece redefino todos los convertidores predeterminados si configuro este convertidor en la Propiedad de ConversionServiceFactoryBean, es Hay alguna forma de mantener los convertidores predeterminados?
  • (nuevamente) ¿Dónde puedo acceder al BindingResult en caso de error en la cadena?
+0

Perdón por ser tan largo, pero esta podría ser una discusión interesante sobre la conversión en Spring – Kartoch

Respuesta

2

Una pregunta bien planteada, incluso se asustará mayoría de la gente fuera :)

De todos modos, creo que la opción (2) es el más cercano a una solución práctica. Mi primera sugerencia es que encapsules la lista de etiquetas en su propia clase de modelo. Esto le dará al marco de enlace de datos un tipo concreto para registrarse, mientras que List y String son demasiado generales.

Así que tendría las clases del modelo:

public class Entry { 
    private String name; 
    private TagList tagList; 
} 


public class TagList { 

    private final List<Tag> tags; 

    public TagList(List<Tag> tags) { 
     this.tags = tags; 
    } 

    public List<Tag> getTags() { 
     return tags; 
    } 
} 

A continuación, tiene un PropertyEditor que sabe cómo convertir hacia y desde un TagList:

public class TagListEditor extends PropertyEditorSupport { 

    @Override 
    public void setAsText(String text) throws IllegalArgumentException { 
     TagList tagList = // parse from the text value 
     setValue(tagList); 
    } 

    @Override 
    public String getAsText() { 
     TagList tagList = (TagList) getValue(); 
     return tagList.toString(); // or whatever 
    } 
} 

Y, por último, es necesario contar la controlador para usar el convertidor:

@Controller 
public class EntryController { 

    @InitBinder 
    public void initBinder(WebDataBinder binder) { 
     binder.registerCustomEditor(TagList.class, new TagListEditor()); 
    } 

    // request mappings here 
} 

Soy bastante s El nuevo marco de Spring 3 Converter produciría una solución más elegante, pero todavía no lo he descubierto :) Sin embargo, este enfoque, sé que funciona.

Cuestiones relacionadas