Java-枚举转换器的通用抽象类
我有一些枚举是名称(“字符串”)和值(“整数”)对,在每个枚举中都是当前的,我必须为Json反序列化实现一个@JsonCreator方法,输入可以是名称或值Java-枚举转换器的通用抽象类,java,enums,abstract-class,generic-programming,Java,Enums,Abstract Class,Generic Programming,我有一些枚举是名称(“字符串”)和值(“整数”)对,在每个枚举中都是当前的,我必须为Json反序列化实现一个@JsonCreator方法,输入可以是名称或值 //User Enum public enum UserType { StakeHolder(1),... private static final Map<String, UserType> helper = ImmutableMap.<String, UserType>builder()
//User Enum
public enum UserType {
StakeHolder(1),...
private static final Map<String, UserType> helper = ImmutableMap.<String, UserType>builder()
.put(String.valueOf(StakeHolder.getValue()), StakeHolder)
.put(StakeHolder.name(), StakeHolder)
.build();
@JsonCreator
public static UserType jsonDeserialize(String json) {
return helper.get(json);
}
}
//Role Enum
public enum RoleType {
Admin(1),...
private static final Map<String, RoleType> helper = ImmutableMap.<String, RoleType>builder()
.put(String.valueOf(Admin.getValue()), Admin)
.put(Admin.name(), Admin)
.build();
@JsonCreator
public static RoleType jsonDeserialize(String json) {
return helper.get(json);
}
}
//用户枚举
公共枚举用户类型{
利益相关者(1),。。。
private static final Map helper=ImmutableMap.builder()
.put(String.valueOf(涉众.getValue()),涉众)
.put(涉众.name(),涉众)
.build();
@JsonCreator
公共静态用户类型jsonDeserialize(字符串json){
返回helper.get(json);
}
}
//角色枚举
公共枚举角色类型{
行政主任(1),。。。
private static final Map helper=ImmutableMap.builder()
.put(String.valueOf(Admin.getValue()),Admin)
.put(Admin.name(),Admin)
.build();
@JsonCreator
公共静态角色类型jsonDeserialize(字符串json){
返回helper.get(json);
}
}
但是我想知道是否有任何方法可以创建一个抽象类来实现整个枚举,即避免在我的每个枚举中实现类似的“重复”代码。当前代码如下
public abstract class JsonDeserializeEnum<E extends Enum<E>> {
// protected Enum<E> myEnums;
// private static final Map<String, E> myEnumHelper; ???
public JsonDeserializeEnum() {
super();
// how to loop through myEnums to do something like
// for(E iterator : myEnums.value()) not work...myEnums is not a collection of enums?
// myEnumHelper.put(String.valueOf(iterator.getValue()), (E) iterator);
// myEnumHelper.put(iterator.name, (E) iterator);
}
@JsonCreator
public static E jsonDeserialize(String json) {
return myEnumHelper.get(json);
}
}
//then
public enum UserType implements JsonDeserializeEnum<UserType>{
StakeHolder(1),...
}
public enum RoleType implements JsonDeserializeEnum<RoleType>{
Admin(1),...
}
公共抽象类JsonDeserializeEnum{
//受保护的髓鞘;
//私有静态最终映射myEnumHelper???
公共JsonDeserializeEnum(){
超级();
//如何通过MyEnum循环执行以下操作
//对于(E迭代器:myEnums.value())不工作…myEnums不是枚举的集合?
//myEnumHelper.put(String.valueOf(iterator.getValue()),(E)iterator);
//myEnumHelper.put(iterator.name,(E)iterator);
}
@JsonCreator
公共静态jsonDeserialize(字符串json){
返回myEnumHelper.get(json);
}
}
//然后
公共枚举用户类型实现JsonDeserializeEnum{
利益相关者(1),。。。
}
公共枚举角色类型实现JsonDeserializeEnum{
行政主任(1),。。。
}
我在这里面临两个挑战
1) 我希望在抽象类中有一个init/构造函数,可以将所有可用的枚举加载到静态映射中(仅一次),例如
调用UserType
时,将所有用户类型enum加载到静态映射中,然后从该映射反序列化;调用RoleType
时,将所有角色类型枚举加载到映射中,然后从同一映射反序列化
2) 如果No.1不可能,那没关系,比如说,如果我将去掉抽象类中的映射,但仍然使用每个枚举中定义的映射,那么我的抽象类是否知道并可以使用枚举中定义的映射?关键是使用
JsonDeserializer
。首先,您需要使用一个接口,以便能够对所有枚举使用相同的代码:
public interface ValueEnum {
String name();
int value();
}
并在每个枚举中实现它
public enum EnumExample implements ValueEnum {
Hello(1),
World(2);
public final int value;
private EnumExample(int value) {
this.value = value;
}
@Override
public int value() {
return value;
}
}
(枚举已经实现了name()
)
然后,您可以将映射创建移动到一个单独的类(我使用java HashMap,您可以使用您喜欢的任何东西)
公共类ValueEnumDeserializer扩展JsonDeserializer{
私有最终哈希映射;
public ValueEnumDeserializer(c类){
map=新的HashMap();
对于(最终ti:c.getEnumConstants()){
map.put(i.name(),i);
map.put(String.valueOf(i.value()),i);
}
}
@凌驾
公共T反序列化(JSONP解析器,反序列化上下文ctxt)
抛出IOException、JsonProcessingException{
返回map.get(p.getText());
}
}
然后,在创建对象映射器时,必须传递反序列化程序
final ObjectMapper mapper = new ObjectMapper();
final SimpleModule module = new SimpleModule();
module.addDeserializer(EnumExample1.class, new ValueEnumDeserializer<>(EnumExample1.class));
module.addDeserializer(EnumExample2.class, new ValueEnumDeserializer<>(EnumExample2.class));
module.addDeserializer(EnumExample3.class, new ValueEnumDeserializer<>(EnumExample3.class));
mapper.registerModule(module);
final ObjectMapper mapper=new ObjectMapper();
最终SimpleModule=新SimpleModule();
module.addDeserializer(EnumExample1.class,新值EnumDeserializer(EnumExample1.class));
module.addDeserializer(EnumExample2.class,新值EnumDeserializer(EnumExample2.class));
module.addDeserializer(EnumExample3.class,新值EnumDeserializer(EnumExample3.class));
映射器注册表模块(模块);
除了建议的实现中的关键冲突之外,主要问题是jsonDeserialize()
必须是静态的。这意味着您必须在每个枚举上声明它。您可以选择将查找逻辑外部化(例如,通过在接口中将映射更改为带有“按枚举类型”条目的映射映射),但这不会有什么改善。明白了!假设我将去掉抽象类中的映射,但仍然使用在每个枚举中定义的映射,那么我的抽象类是否知道并可以使用在枚举中定义的映射?首先,您不能使枚举扩展抽象类。你可以让他们实现一个接口。是的,您可以定义一个契约,使您的枚举实现一个返回本地映射的方法,但它必须是一个实例方法。当你回顾一下这样一个实现时,你可能会发现你的当前版本是两个丑陋的设计中更可取的(我的观点)。哇,这太神奇了!非常感谢。我不太理解的几个问题1)ValueEnumDeserializer中的“映射”,它是否会在每次反序列化json请求时初始化,因为它在类的构造函数中,而不是静态的?2) 在这里,您使用的是“JsonDeserializer”而不是“JsonCreator”,在“反序列化”方法中,“JsonParser”和“反序列化上下文”是否需要使用config进行初始化(比如ignoreCamelCase或其他)?如果是这样,我应该在哪里初始化和注入它们?3) 是否可以将“模块”提取到一个单独的类中?1)仅在每次创建新的ObjectMapper时执行,这应该仅执行一次。2) 配置由创建的ObjectMapper继承,但是忽略驼峰大小写和大多数其他大小写都引用属性名(枚举值不是属性名)。如果希望有多个字符串与枚举匹配,则可以向反序列化器的映射中添加更多值3)是的,只需创建扩展名为
final ObjectMapper mapper = new ObjectMapper();
final SimpleModule module = new SimpleModule();
module.addDeserializer(EnumExample1.class, new ValueEnumDeserializer<>(EnumExample1.class));
module.addDeserializer(EnumExample2.class, new ValueEnumDeserializer<>(EnumExample2.class));
module.addDeserializer(EnumExample3.class, new ValueEnumDeserializer<>(EnumExample3.class));
mapper.registerModule(module);