Tengo un punto final:
/api/offers/search/findByType?type=X donde X debe ser un valor Integer (un valor ordinal de mi instancia de OfferType ), mientras que Spring considera a X como una String y aplicará su StringToEnumConverterFactory con el convertidor StringToEnum .
public interface OfferRepository extends PagingAndSortingRepository<Offer, Long> { List<Offer> findByType(@Param("type") OfferType type); } Así que escribí un Converter<Integer, OfferType> que simplemente obtiene una instancia por el número ordinal dado:
public class IntegerToOfferTypeConverter implements Converter<Integer, OfferType> { @Override public OfferType convert(Integer source) { return OfferType.class.getEnumConstants()[source]; } } Luego lo registré correctamente con una Configuration :
@EnableWebMvc @Configuration @RequiredArgsConstructor public class GlobalMVCConfiguration extends WebMvcConfigurerAdapter { @Override public void addFormatters(FormatterRegistry registry) { registry.addConverter(new IntegerToOfferTypeConverter()); } } Y esperaba que todas las solicitudes de findByType?type=X pasaran a través de mi convertidor, pero no lo hacen.
¿Hay alguna forma de decir que todas las enumeraciones definidas como parámetros de solicitud deben proporcionarse como un Integer ? Además, ¿hay alguna forma de decirlo globalmente, no solo para una enumeración específica?
EDITAR: encontré IntegerToEnumConverterFactory en mi classpath que hace todo lo que necesito. Y está registrado con DefaultConversionService , que es un servicio predeterminado para la conversión. ¿Cómo se puede aplicar eso?
EDIT2: Es algo tan trivial, me preguntaba si hay una propiedad para activar la conversión de enumeración.
EDIT3: Traté de escribir un Converter<String, OfferType> después de obtener String de TypeDescriptor.forObject(value) , no ayudó.
EDIT4: Mi problema fue que había colocado el registro del convertidor personalizado en una configuración MVC ( WebMvcConfigurerAdapter con addFormatters ) en lugar de uno de REST Repositories ( RepositoryRestConfigurerAdapter con configureConversionService ).
Spring analiza los parámetros de consulta como cadenas. Creo que siempre usa los Converter<String, ?> para convertir los parámetros de consulta a los parámetros de los métodos del repositorio. Utiliza un servicio de conversión mejorado, ya que registra sus propios convertidores , como Converter<Entity, Resource> .
Por lo tanto, debe crear un Converter<String, OfferType> , por ejemplo:
@Component public class StringToOfferTypeConverter implements Converter<String, OfferType> { @Override public OfferType convert(String source) { return OfferType.class.getEnumConstants()[Integer.valueOf(source)]; } } Y luego configure este convertidor para que lo use Spring Data REST, en una clase que extienda RepositoryRestConfigurerAdapter :
@Configuration public class ConverterConfiguration extends RepositoryRestConfigurerAdapter { @Autowired StringToOfferTypeConverter converter; @Override public void configureConversionService(ConfigurableConversionService conversionService) { conversionService.addConverter(converter); super.configureConversionService(conversionService); } }Traté de agregar esto al tutorial básico , agregué una enumeración simple a la clase Person:
public enum OfferType { ONE, TWO; } @Entity public class Person { @Id @GeneratedValue(strategy = GenerationType.AUTO) private long id; private OfferType type; public OfferType getType() { return type; } public void setType(OfferType type) { this.type = type; } }Y cuando llamo:
Obtengo el resultado sin errores:
{ "_embedded" : { "people" : [ ] }, "_links" : { "self" : { "href" : "http://localhost:8080/people/search/findByType?type=1" } } } Para implementar un convertidor Enum global, debe crear una fábrica y registrarla en la configuración mediante el método: conversionService.addConverterFactory() . El siguiente código es un ejemplo modificado de la documentación :
public class StringToEnumFactory implements ConverterFactory<String, Enum> { public <T extends Enum> Converter<String, T> getConverter(Class<T> targetType) { return new StringToEnum(targetType); } private final class StringToEnum<T extends Enum> implements Converter<String, T> { private Class<T> enumType; public StringToEnum(Class<T> enumType) { this.enumType = enumType; } public T convert(String source) { Integer index = Integer.valueOf(source); return enumType.getEnumConstants()[index]; } } }