2010-06-22 9 views
5

Ho il seguente (semplificata) forma in uno dei mio punto di vista:Quali sono le migliori strategie di conversione Spring nel caso di una stringa da convertire in un insieme di oggetti?

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

che sta per essere legano al seguente JavaBean:

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

    // setters and getters omitted 
} 

perché voglio prendere uso tutti i nuovi fantasia caratteristiche di Spring 3, che sto utilizzando controller di annotazioni-driven per ricevere la richiesta 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 
    } 
} 

Come potete vedere, ho bisogno di convertire il mio testo di input (che loo k come tag1, tag2, tag3) come una lista di tag, definiscono in questo modo:

public class Tag { 
    private String name; 

    // setter and getter omitted 
} 

C'è diverse strategie per fare questo con la Primavera 3.0:

( spiacenti palo lungo, le domande sono in grassetto)

Il più semplice

Programmazione di una nuova proprietà tagsAsText avere un getter/setter come String:

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

Questo approccio presenta due inconvenienti:

  • ho includono la logica di conversione nel mio oggetto di dominio, è un problema?
  • Dove posso accedere allo BindingResult in caso di errore nella stringa?

Utilizzando BeanInfo

posso anche utilizzare un BeanInfo per il mio fagiolo:

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

E dichiarare un convertitore

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

Questo approccio ha anche due svantaggi:

  • Ho bisogno di modificare il mio BeanInfo ogni volta che aggiungo/cambio la mia classe Entry. o c'è un modo per avere un modo semplice per definire il mio BeanInfo (come "per questa proprietà, utilizzare questo, il resto basta fare come al solito")
  • Dove posso accedere alla BindingResult in caso di errore nella stringa?

Utilizzando Converter

Converter utilizza il meccanismo generico di Java 5:

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

Questo approccio sembra più elegante, ma ancora due inconvenienti:

  • Sembra che io ridefinire tutti i convertitori predefiniti se configuro questo convertitore nella proprietà di ConversionServiceFactoryBean, è c'è un modo per mantenere i convertitori di default?
  • (di nuovo) Dove posso accedere allo BindingResult in caso di errore nella stringa?
+0

Mi spiace essere così lungo, ma questa potrebbe essere una discussione interessante sulla conversione in primavera – Kartoch

risposta

2

Una domanda ben ponderata, anche Sarà spaventare la maggior parte delle persone fuori :)

Comunque, credo che l'opzione (2) è il più vicino ad una soluzione pratica. Il mio primo suggerimento è di incapsulare l'elenco dei tag nella propria classe di modello. Questo darà al framework di associazione dei dati un tipo concreto di registrazione, mentre List e String sono troppo generali.

Così si avrebbe le classi del modello:

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

È quindi hanno un PropertyEditor che sa come convertire da e verso 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 
    } 
} 

E, infine, è necessario dire al controller per utilizzare il convertitore:

@Controller 
public class EntryController { 

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

    // request mappings here 
} 

Sono abbastanza s ure il nuovo framework Converter Spring 3 produrrebbe una soluzione più elegante, ma non l'ho ancora capito :) Questo approccio, comunque, lo so funziona.

Problemi correlati