2011-03-03 13 views
15

He creado muchas clases Enum con int getID() y MyEnum withID(int) métodos que me permiten dedicar una ID a los valores enum para persistencia (evitando cambios debidos a cambio de orden/nombre con respecto al almacenamiento externo) de la enumeración).Conversor personalizado de primavera para todas las Enumeraciones

Me gustaría construir un convertidor personalizado que refleje un poco para buscar estos métodos, y usarlos o hacer una copia de seguridad de las conversiones ordinales/cadenas cuando no se encuentran.

¿Un convertidor Enum genérico le parece posible a alguien? Esta es solo mi segunda incursión en Convertidores.

+1

+1. Me gusta especialmente que esté _ "evitando cambios debido a la orden/nombre" _ –

Respuesta

15

Diría que estás tratando de resolver el problema. Por lo general, persisto enums como cadenas y, por lo tanto, evito este problema en primer lugar. El inconveniente es, por supuesto, un campo DB más grande, pero eso no es significativo.


Dicho esto:

Yo diría que es posible en general, pero no de una manera limpia. Lo que haría es permitir que todas estas enumeraciones implementen una interfaz común (ya sea solo una interfaz de marcador o una que contenga el método int getId()). Ahora registre su PropertyEditor solo para esta interfaz, entonces no está rompiendo demasiada funcionalidad estándar.

Luego, su siguiente problema es que se basa en métodos de fábrica estáticos, lo que no se puede hacer de forma genérica. Por supuesto, su PropertyEditor puede hacer:

enumClass.getDeclaredMethod("withId", int.class).invoke(id) 

pero me gustaría llamar a ese poco limpia. ¿Qué tal algo como esto:

Object target = null; 
for(Object e : EnumSet.allOf(yourEnumClass)){ 
    if(e instanceof MyInterface && ((MyInterface)e).getId()==thisId){ 
     target = e; 
     break; 
    } 
} 
return target; 

Ahora que no está utilizando cualquier método de fábrica estática y que tienen compilar tiempo de seguridad, siempre y cuando sus enumeraciones implementan una interfaz común.


Actualización: con el nuevo convertidor de SPI se hace más fácil. Utilice a custom ConverterFactory:

public class CustomEnumConverterFactory implements 
    ConverterFactory<String, Enum<?>>{ 

    @Override 
    public <T extends Enum<?>> Converter<String, T> getConverter(
     final Class<T> targetType){ 
     return WithId.class.isAssignableFrom(targetType) 
      ? new EnumWithIdConverter(targetType) 
      : new StandardEnumConverter(targetType); 
    } 

} 

Registro de esta manera:

<bean id="conversionService" 
    class="org.springframework.context.support.ConversionServiceFactoryBean"> 
    <property name="converters"> 
     <!-- converters is a set of both converters and converterfactories --> 
     <bean class="foo.bar.CustomEnumConverterFactory" /> 
    </property> 
</bean> 
+0

Excelente respuesta. ¡Gracias! Una pregunta, la interfaz del convertidor no parece darme ninguna forma de saber en qué tipo de Enum está tratando de convertir el String. Mencionaste Editores de propiedades, ¿debería consultar a los Editores de propiedades en lugar de intentar usar el Convertidor SPI más nuevo en primavera? Un valor de [1], por ejemplo, podría ser válido para 10 clases de Enum diferentes. –

+0

@David Oh, mi mal, todavía no estoy muy familiarizado con el conversor SPI, supuse que querías decir PropertyEditor. Déjame comprobar :-) –

+1

Converter SPI es bastante simple, solo tienes que implementar la interfaz: Converter y registrarlo. Pero el único método de conversión que declara pasa solo la Clase de Venta y espera que obtenga una Clase de Cuenta. Por lo tanto, no pasar en Enum o algo así. Pensé que tal vez los editores de propiedades ofrecen una forma diferente de manejar las cosas. Nunca los he visto antes. –

0

se extendía desde WebMvcConfigurerAdapter

@Override 
@SuppressWarnings("unchecked") 
public void addFormatters(FormatterRegistry registry) { 
    registry.addConverterFactory(new ConverterFactory<String, Enum>() { 
     @Override 
     public <T extends Enum> Converter<String, T> getConverter(Class<T> targetType) { 
      return source -> { 
       try { 
        return (T) Enum.valueOf(targetType, source); 
       } catch (Exception e) { 
        return targetType.getEnumConstants()[Integer.parseInt(source)]; 
       } 
      }; 
     } 
    }); 
    super.addFormatters(registry); 
} 
Cuestiones relacionadas