2009-11-20 10 views
10

applicazione I miei Grails ha un gran numero di enumerazioni che assomigliano a questo:Grails legano i parametri di richiesta di enum

public enum Rating { 
    BEST("be"), GOOD("go"), AVERAGE("av"), BAD("ba"), WORST("wo") 
    final String id 

    private RateType(String id) { 
     this.id = id 
    } 

    static public RateType getEnumFromId(String value) { 
     values().find {it.id == value } 
    } 
} 

Se ho un oggetto comando come questo:

class MyCommand { 
    Rating rating 
} 

Vorrei per (ad esempio) convertire automaticamente un parametro di richiesta con valore "wo" in Rating.WORST.

La procedura per la definizione dei convertitori personalizzati è descritta con here (nel contesto della conversione di stringhe in date). Sebbene questa procedura funzioni correttamente, non voglio dover creare una classe che implementa PropertyEditorSupport per ciascuna delle mie enumerazioni. C'è un'alternativa migliore?

risposta

11

ho trovato una soluzione Sono abbastanza contento.

Fase 1: Creare un'implementazione di PropertyEditorSupport per convertire il testo da/per il relativo Enum

public class EnumEditor extends PropertyEditorSupport { 

    private Class<? extends Enum<?>> clazz 

    public EnumEditor(Class<? extends Enum<?>> clazz) { 
     this.clazz = clazz 
    } 

    public String getAsText() { 
     return value?.id 
    } 

    public void setAsText(String text) { 
     value = clazz.getEnumFromId(text) 
    } 
} 

Fase 2: Definire una classe che registra EnumEditor come convertitore per le varie classi enum. Per modificare l'elenco delle classi enum che sono associabile da id, basta modificare BINDABLE_ENUMS

public class CustomPropertyEditorRegistrar implements PropertyEditorRegistrar { 

    private static final String REQUIRED_METHOD_NAME = 'getEnumFromId' 

    // Add any enums that you want to bind to by ID into this list 
    private static final BINDABLE_ENUMS = [Rating, SomeOtherEnum, SomeOtherEnum2] 

    public void registerCustomEditors(PropertyEditorRegistry registry) {    

     BINDABLE_ENUMS.each {enumClass -> 
      registerEnum(registry, enumClass) 
     } 
    } 

    /** 
    * Register an enum to be bound by ID from a request parameter 
    * @param registry Registry of types eligible for data binding 
    * @param enumClass Class of the enum 
    */ 
    private registerEnum(PropertyEditorRegistry registry, Class<? extends Enum<?>> enumClass) { 

     boolean hasRequiredMethod = enumClass.metaClass.methods.any {MetaMethod method -> 
      method.isStatic() && method.name == REQUIRED_METHOD_NAME && method.parameterTypes.size() == 1 
     } 

     if (!hasRequiredMethod) { 
      throw new MissingMethodException(REQUIRED_METHOD_NAME, enumClass, [String].toArray()) 
     } 
     registry.registerCustomEditor(enumClass, new EnumEditor(enumClass)) 
    } 
} 

Fase 3: Fai Primavera a conoscenza del Registro di sistema definendo la seguente bean Spring in grails-app/conf/spring/resources.grooovy

customPropertyEditorRegistrar(CustomPropertyEditorRegistrar) 
+0

Buon lavoro! Sto lottando con lo stesso problema. Perché diavolo non è una parte standard di Grails? Il supporto di Grails per i parametri di richiesta di binding agli oggetti dominio/comando è davvero terribile. – mcv

+3

Grails supporta i parametri di richiesta di associazione alle enumerazioni, ma l'associazione predefinita si associa per nome. Se vuoi vincolare da qualche altra proprietà enum (ad es. Per id, come sopra), devi definire tu stesso il legame –

10

Quindi il Databinding predefinito si associa al nome Enum e non a una proprietà definita separatamente dell'Enum. È possibile create your own PropertyEditor come lei ha detto o fare un work-around simile a questo:

class MyCommand { 
String ratingId 
    Rating getRating() { 
    return Rating.getEnumFromId(this.ratingId) 
    } 
    static constraints = { 
    ratingId(validator:{val, obj -> Rating.getEnumFromId(val) != null }) 
    } 
} 
+0

Impressionante soluzione alternativa Colin! –

Problemi correlati