Jam*_*mes 5 java generics enums spring spring-mvc
正如如何获取枚举的 valueOf 和值并在定义为泛型类 param 时调用其实现的接口上的方法中提到的,我想将字符串转换为枚举以获得一组枚举类型。虽然那篇文章中的答案解决了我的编译问题,但 Spring 没有转换(请参阅下面的更新)。以下是该帖子中的信息,供参考:
我使用一个接口来标记要转换的枚举集,并定义转换期间使用的几个方法:
public interface SymbolEnum {
String getCode();
String getDescription();
}
Run Code Online (Sandbox Code Playgroud)
下面是我想要从字符串派生的枚举类型之一的示例:
@RequiredArgsConstructor // using lombok
public enum Element implements SymbolEnum {
IRON("FE", "iron"),
HYDROGEN("H", "hydrogen"),
@Getter
private final String code;
@Getter
private final String description;
}
Run Code Online (Sandbox Code Playgroud)
如果字符串与枚举常量名称、枚举代码属性或枚举描述属性匹配,那么我想转换为该枚举。否则,代码应该抛出 IllegalArgumentException。
我正在使用 Spring 的 Converter 接口来实现我的转换器:
@RequiredArgsConstructor
public class StringToSymbolEnum<T extends Enum<T> & SymbolEnum> implements Converter<String, T> {
private final T[] values;
@Override
public T convert(String source) {
try {
return Enum.valueOf(values[0].getDeclaringClass(), source);
} catch (IllegalArgumentException notEnumConstant) {
for (T value : values()) {
if (value.getDescription().equalsIgnoreCase(source)
|| value.getCode().equalsIgnoreCase(source)) {
return value;
}
}
throw notEnumConstant;
}
}
}
Run Code Online (Sandbox Code Playgroud)
这是我注册转换器的地方:
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new StringToSymbolEnum<Element>(Element.values()));
}
}
Run Code Online (Sandbox Code Playgroud)
但转换器从未被调用。如何让 Spring 使用转换器?
更新
我希望当向控制器中的以下端点发出 HTTP GET 请求时调用转换器:
@RestController
@RequiredArgsConstructor
@RequestMapping("/element")
public class ElementController {
@NonNull
private final ElementService elementService;
@GetMapping
public Element getElement(
@RequestParam(name="element")
Element element // During Spring's binding, I expect the registered converter to be called
) {
return elementService.getElement(element);
}
}
Run Code Online (Sandbox Code Playgroud)
更新2
我找到了解决这个问题的几个方法。一种解决方案是实现 SpringConverterFactory并将其注册到FormatterRegistry. 但是,该解决方案似乎更适合注册单个超类型。在我的示例中,如果类有两种类型,则需要注册SymbolEnum和Enum。这是我对这种方法的尝试:
public class StringToEnumConverterFactory <R extends Enum<R> & SymbolEnum>
implements ConverterFactory<String, R> {
@Override
public <T extends R> Converter<String, T> getConverter(Class<T> targetType) {
return new StringToSymbolEnumInner<T>(targetType.getEnumConstants());
}
private class StringToSymbolEnumInner <W extends R>
implements Converter<String, W> {
private final W[] values;
public StringToSymbolEnumInner(W[] values) {
this.values = values;
}
@SuppressWarnings("unchecked")
@Override
public W convert(String source) {
log.info("called converter with values ");
try {
return (W) Enum.valueOf(values[0].getDeclaringClass(), source);
} catch (IllegalArgumentException notEnumConstant) {
for (W value : values) {
if (value.getDescription().equalsIgnoreCase(source)
|| value.getCode().equalsIgnoreCase(source)) {
return value;
}
}
throw notEnumConstant;
}
}
}
Run Code Online (Sandbox Code Playgroud)
我不喜欢演员阵容,而且它真的不能像工厂一样工作,因为我必须注册每个SymbolEnum班级。
另一种选择是使用更明确的注册,如下所示:
registry.addConverter(String.class,
Element.class,
new StringToSymbolEnum<Element>(
Element.values()));
Run Code Online (Sandbox Code Playgroud)
这两种方法都有效。也就是说,转换器被调用。有更好的方法吗?为什么我的第一次尝试没有成功?我想知道这是否与类型擦除有关。
| 归档时间: |
|
| 查看次数: |
1756 次 |
| 最近记录: |