Java-枚举转换器的通用抽象类

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()

我有一些枚举是名称(“字符串”)和值(“整数”)对,在每个枚举中都是当前的,我必须为Json反序列化实现一个@JsonCreator方法,输入可以是名称或值

//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);