Spring 数据 JPA 方法 + REST:枚举到整数的转换
Spring Data JPA method + REST: Enum to Integer conversion
我有一个端点:
/api/offers/search/findByType?type=X
其中 X
应该是一个 Integer
值(我的 OfferType
实例的序数值),而 Spring 认为 X
是 String
并将其 StringToEnumConverterFactory
与 StringToEnum
转换器一起应用。
public interface OfferRepository extends PagingAndSortingRepository<Offer, Long> {
List<Offer> findByType(@Param("type") OfferType type);
}
所以我写了一个自定义 Converter<Integer, OfferType>
它只是通过给定的序号获得一个实例:
public class IntegerToOfferTypeConverter implements Converter<Integer, OfferType> {
@Override
public OfferType convert(Integer source) {
return OfferType.class.getEnumConstants()[source];
}
}
然后我用 Configuration
:
正确注册了它
@EnableWebMvc
@Configuration
@RequiredArgsConstructor
public class GlobalMVCConfiguration extends WebMvcConfigurerAdapter {
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new IntegerToOfferTypeConverter());
}
}
并且我希望 findByType?type=X
的所有请求都将通过我的转换器,但它们没有。
有什么方法可以说所有定义为请求参数的枚举都必须作为 Integer
提供?此外,有没有什么办法可以在全球范围内说出来,而不仅仅是针对特定的枚举?
编辑: 我在我的类路径中发现 IntegerToEnumConverterFactory
可以满足我的所有需求。它在 DefaultConversionService
中注册,这是默认的转换服务。如何应用?
EDIT2: 这么琐碎的事情,我想知道是否有 属性 打开枚举转换。
EDIT3: 在从 TypeDescriptor.forObject(value)
得到 String
之后,我试图写一个 Converter<String, OfferType>
,但没有帮助。
EDIT4: 我的问题是我将自定义转换器注册放入 MVC 配置(WebMvcConfigurerAdapter
和 addFormatters
)而不是 REST 存储库(RepositoryRestConfigurerAdapter
与 configureConversionService
)。
Spring 将查询参数解析为字符串。我相信它总是使用 Converter<String, ?>
转换器将查询参数转换为存储库方法参数。它使用增强型转换器服务,因为它注册 its own converters 例如 Converter<Entity, Resource>
.
因此你必须创建一个Converter<String, OfferType>
,例如:
@Component
public class StringToOfferTypeConverter implements Converter<String, OfferType> {
@Override
public OfferType convert(String source) {
return OfferType.class.getEnumConstants()[Integer.valueOf(source)];
}
}
然后配置此转换器以供 Spring 数据 REST 使用,在 class 扩展 RepositoryRestConfigurerAdapter
:
中
@Configuration
public class ConverterConfiguration extends RepositoryRestConfigurerAdapter {
@Autowired
StringToOfferTypeConverter converter;
@Override
public void configureConversionService(ConfigurableConversionService conversionService) {
conversionService.addConverter(converter);
super.configureConversionService(conversionService);
}
}
我试图将其添加到 the basic tutorial,向 Person 添加了一个简单的枚举 class:
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;
}
}
当我打电话时:
我得到的结果没有错误:
{
"_embedded" : {
"people" : [ ]
},
"_links" : {
"self" : {
"href" : "http://localhost:8080/people/search/findByType?type=1"
}
}
}
要实现一个全局枚举转换器,您必须创建一个工厂并使用以下方法在配置中注册它:conversionService.addConverterFactory()
。下面的代码是修改后的 example from the documentation:
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];
}
}
}
我有一个端点:
/api/offers/search/findByType?type=X
其中 X
应该是一个 Integer
值(我的 OfferType
实例的序数值),而 Spring 认为 X
是 String
并将其 StringToEnumConverterFactory
与 StringToEnum
转换器一起应用。
public interface OfferRepository extends PagingAndSortingRepository<Offer, Long> {
List<Offer> findByType(@Param("type") OfferType type);
}
所以我写了一个自定义 Converter<Integer, OfferType>
它只是通过给定的序号获得一个实例:
public class IntegerToOfferTypeConverter implements Converter<Integer, OfferType> {
@Override
public OfferType convert(Integer source) {
return OfferType.class.getEnumConstants()[source];
}
}
然后我用 Configuration
:
@EnableWebMvc
@Configuration
@RequiredArgsConstructor
public class GlobalMVCConfiguration extends WebMvcConfigurerAdapter {
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new IntegerToOfferTypeConverter());
}
}
并且我希望 findByType?type=X
的所有请求都将通过我的转换器,但它们没有。
有什么方法可以说所有定义为请求参数的枚举都必须作为 Integer
提供?此外,有没有什么办法可以在全球范围内说出来,而不仅仅是针对特定的枚举?
编辑: 我在我的类路径中发现 IntegerToEnumConverterFactory
可以满足我的所有需求。它在 DefaultConversionService
中注册,这是默认的转换服务。如何应用?
EDIT2: 这么琐碎的事情,我想知道是否有 属性 打开枚举转换。
EDIT3: 在从 TypeDescriptor.forObject(value)
得到 String
之后,我试图写一个 Converter<String, OfferType>
,但没有帮助。
EDIT4: 我的问题是我将自定义转换器注册放入 MVC 配置(WebMvcConfigurerAdapter
和 addFormatters
)而不是 REST 存储库(RepositoryRestConfigurerAdapter
与 configureConversionService
)。
Spring 将查询参数解析为字符串。我相信它总是使用 Converter<String, ?>
转换器将查询参数转换为存储库方法参数。它使用增强型转换器服务,因为它注册 its own converters 例如 Converter<Entity, Resource>
.
因此你必须创建一个Converter<String, OfferType>
,例如:
@Component
public class StringToOfferTypeConverter implements Converter<String, OfferType> {
@Override
public OfferType convert(String source) {
return OfferType.class.getEnumConstants()[Integer.valueOf(source)];
}
}
然后配置此转换器以供 Spring 数据 REST 使用,在 class 扩展 RepositoryRestConfigurerAdapter
:
@Configuration
public class ConverterConfiguration extends RepositoryRestConfigurerAdapter {
@Autowired
StringToOfferTypeConverter converter;
@Override
public void configureConversionService(ConfigurableConversionService conversionService) {
conversionService.addConverter(converter);
super.configureConversionService(conversionService);
}
}
我试图将其添加到 the basic tutorial,向 Person 添加了一个简单的枚举 class:
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;
}
}
当我打电话时:
我得到的结果没有错误:
{
"_embedded" : {
"people" : [ ]
},
"_links" : {
"self" : {
"href" : "http://localhost:8080/people/search/findByType?type=1"
}
}
}
要实现一个全局枚举转换器,您必须创建一个工厂并使用以下方法在配置中注册它:conversionService.addConverterFactory()
。下面的代码是修改后的 example from the documentation:
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];
}
}
}