Java - 枚举转换器的通用摘要 class
Java - Generic abstract class for Enum Converter
我有一些枚举,它们是名称("String")和值("Integer")对,当前在每个枚举中我必须为 [= 实现一个@JsonCreator 方法36=]反序列化输入可以是名称或值
//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);
}
}
但我想知道是否有任何方法可以创建一个抽象 class 可以实现整体枚举,这是为了避免在我的每个枚举中始终实现类似的 "duplicate" 代码。当前代码就像
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),...
}
我在这里遇到了两个挑战,
1) 我想在我的摘要 class 中有一个 init/constructor 可以将所有可用的枚举加载到静态映射中(仅一次),例如
调用UserType
时,将所有用户类型枚举加载到静态映射中,然后从该映射反序列化;调用 RoleType
时,将所有角色类型枚举加载到映射中,然后从同一映射反序列化
2) 如果 No.1 不可能,没关系,假设我是否会在我的抽象 class 中删除地图,但仍然使用我的每个枚举中定义的地图,是否有无论如何,我的摘要 class 知道并可以使用我的 Enum 中定义的地图?
关键是要用一个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()
已由枚举实现)
然后你可以将你的地图创建移动到一个单独的class(我使用java HashMap,你可以使用任何你喜欢的)
public class ValueEnumDeserializer<T extends ValueEnum> extends JsonDeserializer<T> {
private final HashMap<String, T> map;
public ValueEnumDeserializer(Class<T> c) {
map = new HashMap<>();
for (final T i : c.getEnumConstants()) {
map.put(i.name(), i);
map.put(String.valueOf(i.value()), i);
}
}
@Override
public T deserialize(JsonParser p, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
return 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);
我有一些枚举,它们是名称("String")和值("Integer")对,当前在每个枚举中我必须为 [= 实现一个@JsonCreator 方法36=]反序列化输入可以是名称或值
//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);
}
}
但我想知道是否有任何方法可以创建一个抽象 class 可以实现整体枚举,这是为了避免在我的每个枚举中始终实现类似的 "duplicate" 代码。当前代码就像
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),...
}
我在这里遇到了两个挑战,
1) 我想在我的摘要 class 中有一个 init/constructor 可以将所有可用的枚举加载到静态映射中(仅一次),例如
调用UserType
时,将所有用户类型枚举加载到静态映射中,然后从该映射反序列化;调用 RoleType
时,将所有角色类型枚举加载到映射中,然后从同一映射反序列化
2) 如果 No.1 不可能,没关系,假设我是否会在我的抽象 class 中删除地图,但仍然使用我的每个枚举中定义的地图,是否有无论如何,我的摘要 class 知道并可以使用我的 Enum 中定义的地图?
关键是要用一个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()
已由枚举实现)
然后你可以将你的地图创建移动到一个单独的class(我使用java HashMap,你可以使用任何你喜欢的)
public class ValueEnumDeserializer<T extends ValueEnum> extends JsonDeserializer<T> {
private final HashMap<String, T> map;
public ValueEnumDeserializer(Class<T> c) {
map = new HashMap<>();
for (final T i : c.getEnumConstants()) {
map.put(i.name(), i);
map.put(String.valueOf(i.value()), i);
}
}
@Override
public T deserialize(JsonParser p, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
return 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);