2009-11-20 13 views
10

aplicación Mis Grails tiene un gran número de enumeraciones que se parecen a esto:Griales unen parámetros de la petición es posible enumerar los

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

Si tengo un objeto de comando como este:

class MyCommand { 
    Rating rating 
} 

me gustaría para (por ejemplo) convertir automáticamente un parámetro de solicitud con el valor "wo" a Rating.WORST.

El procedimiento para definir convertidores personalizados se describe here (en el contexto de la conversión de cadenas a fechas). Aunque este procedimiento funciona bien, no quiero tener que crear una clase que implemente PropertyEditorSupport para cada una de mis enums. ¿Hay una mejor alternativa?

Respuesta

11

he encontrado una solución que estoy bastante contento con el.

Paso 1: Crear una implementación de PropertyEditorSupport para convertir texto a/desde el Enum relevante

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

Paso 2: Definir una clase que registra EnumEditor como un convertidor para las distintas clases de enumeración. Para cambiar la lista de clases de enumeración que son enlazables por id, basta con modificar 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)) 
    } 
} 

Paso 3: Hacer primavera consciente del registro anterior mediante la definición de la siguiente frijol de primavera en grails-app/conf/spring/resources.grooovy

customPropertyEditorRegistrar(CustomPropertyEditorRegistrar) 
+0

¡Buen trabajo! Estoy luchando con el mismo problema. ¿Por qué diablos no es esta una parte estándar de Grails? El soporte de Grails para enlazar parámetros de solicitud a objetos de dominio/comando es realmente horrible. – mcv

+3

Grails admite los parámetros de solicitud de enlace a enumeraciones, pero el valor predeterminado se vincula por nombre. Si desea enlazar con alguna otra propiedad enum (por ejemplo, mediante id, como se indica anteriormente), debe definir el enlace usted mismo –

10

Por lo tanto, el enlace de datos predeterminado se une al nombre de Enum y no a una propiedad de Enum definida por separado. Puede create your own PropertyEditor como usted ha mencionado, o hacer un trabajo en torno similar a esto:

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

impresionante solución alternativa Colin! –

Cuestiones relacionadas