在java或各种框架中,[反]序列化对枚举类型默认一般都是用的枚举的名称。 如果代码有魔法值,我们想改成枚举类型。但我们在改造、重构后端的时候不想对前端或者第三方有影响,可以用到此方法。
必须用到的枚举工具类
参考通用枚举 通用枚举 所有的枚举想要实现(反)序列化比较要用到通用枚举,实现通用枚举的接口即可
代码(最初版本) 1.可反序列化的枚举
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 public enum DeserializableEnum { DB_Enum(DBEnum.class, DBEnum::getValue, DB_Enum::getDoc), I_Enum(IEnum.class, IEnum::getIdentity, IEnum::getDoc), I_Enums(IEnums.class, IEnums::getIdentities, IEnums::getDoc), ; private final Class<?> enumInterface; private final Function<Object, Serializable> getIdentityFunction; private final Function<Object, String> getDocFunction; <T> DeserializableEnum(Class<T> enumInterface, Function<T, Serializable> getIdentityFunction, Function<T, String> getDocFunction) { this .enumInterface = enumInterface; this .getIdentityFunction = (Function<Object, Serializable>) getIdentityFunction; this .getDocFunction = (Function<Object, String>) getDocFunction; } public static Optional<DeserializableEnum> getDeserializableEnum (Class<?> enumClass) { if (enumClass == null ) { return Optional.empty(); } if (!enumClass.isEnum()) { return Optional.empty(); } for (DeserializableEnum deserializableEnum : DeserializableEnum.values()) { if (deserializableEnum.enumInterface.isAssignableFrom(enumClass)) { return Optional.of(deserializableEnum); } } return Optional.empty(); } private Enum<?> deserializeEnum(Class<Enum<?>> enumClass, Object rawValue) { for (Enum<?> enumConstant : enumClass.getEnumConstants()) { Serializable identity = this .getGetIdentityFunction.apply(enumConstant); if (Objects.equals(identity, rawValue)) { return enumConstant; } if (identity instanceof Object[]) { for (Object i : (Object[]) identity) { if (Objects.equals(i, rawValue)) { return enumConstant; } } } } if (rawValue == null || StringUtils.isBlank(rawValue.toString())) { return null ; } throw new EnumDeserializeException(MessageFormat.format("参数错误,无法匹配对应的类型,value:{0}, type:{1}" , rawValue, enumClass.getSimpleName())); } }
2.枚举[反]序列化的各种框架配置
如jackson,fastjson,springConvert等
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 public class EnumDeserializerImpls { public static final GenericConverter ENUM_DESERIALIZER_CONVERTER = new GenericConverter() { @Override public Set<ConvertiblePair> getConvertibleTypes () { Set<ConvertiblePair> cpSet = Sets.newHashSet(); for (DeserializableEnum deserializableEnum : DeserializableEnum.values()) { cpSet.add(new ConvertiblePair(String.class, deserializableEnum.enumInterface)); cpSet.add(new ConvertiblePair(Number.class, deserializableEnum.enumInterface)); } return cpSet; } @Override public Object convert (Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { ResolvableType targetResolvableType = targetType.getResolvableType(); Class<?> valueRawClass = getValueRawClass(targetResolvableType); if (valueRawClass == null ) { return source; } Class<Enum<?>> enumClass = (Class<Enum<?>>) targetResolvableType.resolve(); DeserializableEnum deserializableEnum = DeserializableEnum.getDeserializableEnum(enumClass).orElse(null ); if (deserializableEnum == null ) { return source; } Object rawValue = DefaultConversionService.getSharedInstance().convert(source, valueRawClass); return deserializableEnum.deserializeEnum(enumClass, rawValue); } }; public static final SimpleModule ENUM_MODULE = new SimpleModule() { @Override public void setupModule (SetupContext context) { context.addDeserializers(new Deserializers.Base() { @Override public JsonDeserializer<?> findEnumDeserializer(Class<?> type, DeserializationConfig config, BeanDescription beanDesc) { Class<?> valueRawClass = getValueRawClass(ResolvableType.forClass(type)); if (valueRawClass == null ) { return null ; } return DeserializableEnum.getDeserializableEnum(type) .map(deserializableEnum -> new JsonDeserializer<Enum<?>>() { @Override public Enum<?> deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException { Object value = DefaultConversionService.getSharedInstance().convert(jsonParser.getValueAsString(), valueRawClass); return deserializableEnum.deserializeEnum((Class<Enum<?>>) type, value); } }).orElse(null ); } }); } }; public static final Module FASTJSON_MODULE = new Module() { @Override public ObjectDeserializer createDeserializer (ParserConfig config, Class type) { Class<?> valueRawClass = getValueRawClass(ResolvableType.forClass(type)); if (valueRawClass == null ) { return null ; } return DeserializableEnum.getDeserializableEnum(type) .map(deserializableEnum -> new ObjectDeserializer() { @Override public <T> T deserialze (DefaultJSONParser parser, Type type, Object fieldName) { Object value = parser.parse(); Object rawValue = DefaultConversionService.getSharedInstance().convert(value, valueRawClass); return (T) deserializableEnum.deserializeEnum((Class<Enum<?>>) type, rawValue); } public int getFastMatchToken () { return JSONToken.LITERAL_STRING; } }).orElse(null ); } @Override public ObjectSerializer createSerializer (SerializeConfig config, Class type) { return null ; } }; public static Class<?> getValueRawClass(ResolvableType realClassResolvedType) { ResolvableType[] enumInterfaces = realClassResolvedType.getInterfaces(); if (ArrayUtils.isEmpty(enumInterfaces)) { return null ; } ResolvableType valueResolvableType = enumInterfaces[0 ].getGeneric(0 ); if (valueResolvableType == ResolvableType.NONE) { return null ; } return valueResolvableType.getRawClass(); } }
缺陷 1:目前不支持序列化😝 2:获取枚举identity类型的方法比较愚钝,一刀切了
如果是间接实现的枚举或者泛型的位置不在第一个位置,那就有问题喽。
3:反序列化和序列化只能单层序列和反序列,什么意思呢?
枚举的标识可以获取到枚举对吧?如果枚举的标识还是一个枚举呢?目前只支持序列化和反序列化最外一层的value。太抽象?
代码(新版本)
支持序列化啦
支持枚举内嵌的标识序列化和反序列化
更精准的获取泛型上的标识
1.可反序列化的枚举
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 public enum DeserializableEnum { DB_Enum(DBEnum.class, 0 , DBEnum::getValue, DBEnum::getDoc), I_Enum(IEnum.class, 0 , IEnum::getIdentity, IEnum::getDoc), I_Enums(IEnums.class, 0 , IEnums::getIdentities, IEnums::getDoc), ; public final Class<?> enumInterface; private final int identityGenericIndex; private final Function<Enum<?>, Serializable> getIdentityFunction; public final Function<Enum<?>, String> getDocFunction; <T> DeserializableEnum(Class<T> enumInterface, int identityGenericIndex, Function<T, Serializable> getIdentityFunction, Function<T, String> getDocFunction) { this .enumInterface = enumInterface; this .identityGenericIndex = identityGenericIndex; this .getIdentityFunction = (Function<Enum<?>, Serializable>) getIdentityFunction; this .getDocFunction = (Function<Enum<?>, String>) getDocFunction; } private Enum<?> deserializeEnum(Class<Enum<?>> enumClass, Object rawValue) { for (Enum<?> enumConstant : enumClass.getEnumConstants()) { Object identity = getIdentity(enumConstant); if (identity instanceof Object[]) { for (Object i : (Object[]) identity) { if (Objects.equals(i, rawValue)) { return enumConstant; } } } else { if (Objects.equals(identity, rawValue)) { return enumConstant; } } } if (rawValue == null || StringUtils.isBlank(rawValue.toString())) { return null ; } throw new EnumDeserializeException(MessageFormat.format("参数错误,无法匹配对应的类型,value:{0}, type:{1}" , rawValue, enumClass.getSimpleName())); } public Object getIdentity (Enum<?> enumConstant) { Serializable identity = this .getIdentityFunction.apply(enumConstant); if (identity == null ) { return null ; } Class<?> identityType; if (identity instanceof Object[]) { identityType = identity.getClass().getComponentType(); } else { identityType = identity.getClass(); } DeserializableEnum deserializableEnum = getDeserializableEnumAndIdentityClass(identityType) .map(Map.Entry::getKey) .orElse(null ); if (deserializableEnum == null || !(identity instanceof Enum<?>)) { return identity; } return deserializableEnum.getIdentity((Enum<?>) identity); } private Class<?> getValueRawClass(Class<?> enumInterface) { ResolvableType resolvableType = ResolvableType.forClass(enumInterface).as(this .enumInterface); Class<?> valueRawClass = resolvableType.getGeneric(this .identityGenericIndex).resolve(); DeserializableEnum deserializableEnum = DeserializableEnum.getDeserializableEnumAndIdentityClass(valueRawClass) .map(Map.Entry::getKey) .orElse(null ); if (deserializableEnum == null ) { return valueRawClass; } return deserializableEnum.getValueRawClass(valueRawClass); } public static Optional<Map.Entry<DeserializableEnum, Class<?>>> getDeserializableEnumAndIdentityClass(Class<?> enumClass) { if (enumClass == null ) { return Optional.empty(); } if (!enumClass.isEnum()) { return Optional.empty(); } for (DeserializableEnum deserializableEnum : DeserializableEnum.values()) { if (deserializableEnum.enumInterface.isAssignableFrom(enumClass)) { Class<?> identityValueRawClass = deserializableEnum.getValueRawClass(enumClass); return Optional.of(Pair.of(deserializableEnum, identityValueRawClass)); } } return Optional.empty(); } }
2.枚举[反]序列化的各种框架配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 @Slf4j public class EnumDeserializerImpls { public static final GenericConverter ENUM_DESERIALIZER_CONVERTER = new GenericConverter() { @Override public Set<ConvertiblePair> getConvertibleTypes () { Set<ConvertiblePair> cpSet = Sets.newHashSet(); for (DeserializableEnum deserializableEnum : DeserializableEnum.values()) { cpSet.add(new ConvertiblePair(String.class, deserializableEnum.enumInterface)); cpSet.add(new ConvertiblePair(Number.class, deserializableEnum.enumInterface)); } return cpSet; } @Override public Object convert (Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { Class<?> targetClass = targetType.getResolvableType().resolve(); return DeserializableEnum.getDeserializableEnumAndIdentityClass(targetClass) .map((Function<Map.Entry<DeserializableEnum, Class<?>>, Object>) entry -> { Object rawValue = DefaultConversionService.getSharedInstance().convert(source, entry.getValue()); return entry.getKey().deserializeEnum((Class<Enum<?>>) targetClass, rawValue); }).orElse(null ); } }; public static final SimpleModule ENUM_MODULE = new SimpleModule() { @Override public void setupModule (SetupContext context) { context.addSerializers(new Serializers.Base() { @Override public JsonSerializer<?> findSerializer(SerializationConfig config, JavaType type, BeanDescription beanDesc) { return DeserializableEnum.getDeserializableEnumAndIdentityClass(type.getRawClass()) .map(Map.Entry::getKey) .map(deserializableEnum -> new JsonSerializer<Enum<?>>() { @Override public void serialize (Enum<?> o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { jsonGenerator.writeObject(deserializableEnum.getIdentity(o)); } }).orElse(null ); } }); context.addDeserializers(new Deserializers.Base() { @Override public JsonDeserializer<?> findEnumDeserializer(Class<?> type, DeserializationConfig config, BeanDescription beanDesc) { return DeserializableEnum.getDeserializableEnumAndIdentityClass(type) .map(entry -> new JsonDeserializer<Enum<?>>() { public Enum<?> deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException { Object value = DefaultConversionService.getSharedInstance().convert(jsonParser.getValueAsString(), entry.getValue()); return entry.getKey().deserializeEnum((Class<Enum<?>>) type, value); } }).orElse(null ); } }); } }; public static final Module FASTJSON_MODULE = new Module() { @Override public ObjectDeserializer createDeserializer (ParserConfig config, Class type) { return DeserializableEnum.getDeserializableEnumAndIdentityClass(type) .map(entry -> new ObjectDeserializer() { @Override public <T> T deserialze (DefaultJSONParser parser, Type type, Object fieldName) { Object rawValue = DefaultConversionService.getSharedInstance().convert(parser.parse(), entry.getValue()); return (T) entry.getKey().deserializeEnum((Class<Enum<?>>) type, rawValue); } @Override public int getFastMatchToken () { return JSONToken.LITERAL_STRING; } }).orElse(null ); } @Override public ObjectSerializer createSerializer (SerializeConfig config, Class type) { return DeserializableEnum.getDeserializableEnumAndIdentityClass(type) .map(entry -> new ObjectSerializer() { @Override public void write (JSONSerializer serializer, Object object, Object fieldName, Type fieldType, int features) { serializer.write(entry.getKey().getIdentity((Enum<?>) object)); } }).orElse(null ); } }; }
基本实现以及各种框架的组件都已经定义出来了,可以参考springMvc枚举序列化和反序列化 ,把这些实现应用到实际的项目当中。 然后我们用各种枚举什么的,后端可以安心的进行重构(使用)了
新代码用到了递归,如果不理解旧代码的话阅读起来比较复杂。建议先理解旧代码在阅读新代码