自定义枚举序列化与反序列化
抽象枚举接口
package com.example.common.properties.enums;
import cn.hutool.core.util.ObjectUtil;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public interface IEnum {
Map<Class<?>, Map<String, Enum<?>>> cache = new ConcurrentHashMap<>();
static <T> T codeOf(Class<T> clazz, String code){
Map<String, Enum<?>> map = cache.get(clazz);
if (ObjectUtil.isEmpty(map)){
map = new ConcurrentHashMap<>();
Object[] items = clazz.getEnumConstants();
if (items == null) return null;
for (Object item : items) {
if (item instanceof IEnum){
IEnum iEnum = (IEnum) item;
map.put(iEnum.value(), (Enum<?>) item);
}
}
cache.put(clazz, map);
}
return (T) map.get(code);
}
String value();
String desc();
}
定义枚举
package com.example.common.properties.enums;
public enum Status implements IEnum {
ACTION("1"), INACTION("0");
private String value;
Status(String value){this.value = value;}
@Override
public String value() {
return value;
}
@Override
public String desc() {
return null;
}
}
定义序列化器
package com.example.common.jackson;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.example.common.properties.enums.IEnum;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
public class EnumsJacksonSerializer extends JsonSerializer<IEnum> {
@Override
public void serialize(IEnum iEnum, JsonGenerator generator, SerializerProvider provider) throws IOException {
Map<Object, Object> map = new HashMap<>();
map.put("code", iEnum.value());
map.put("desc", iEnum.desc());
generator.writeObject(map);
}
public static EnumsJacksonSerializer instance(){
return new EnumsJacksonSerializer();
}
}
定义反序列化器
package com.example.common.jackson;
import cn.hutool.core.util.ReflectUtil;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.example.common.properties.enums.IEnum;
import java.io.IOException;
import java.lang.reflect.Field;
public class EnumsJacksonDeserializer extends JsonDeserializer<IEnum> {
@Override
public IEnum deserialize(JsonParser parser, DeserializationContext context) throws IOException {
Field field = ReflectUtil.getField(parser.getCurrentValue().getClass(), parser.getCurrentName());
return (IEnum) IEnum.codeOf(field.getType(), parser.getText());
}
public static EnumsJacksonDeserializer instance(){
return new EnumsJacksonDeserializer();
}
}
配置
package com.example.config;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.module.SimpleDeserializers;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.type.ClassKey;
import com.example.common.jackson.EnumsJacksonDeserializer;
import com.example.common.jackson.EnumsJacksonSerializer;
import com.example.common.properties.enums.IEnum;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
@Configuration
public class JacksonConfig {
@Bean
public ObjectMapper objectMapper(Jackson2ObjectMapperBuilder builder) {
SimpleDeserializersWrapper deserializers = new SimpleDeserializersWrapper();
deserializers.addDeserializer(IEnum.class, new EnumsJacksonDeserializer());
SimpleModule simpleModule = new SimpleModule();
simpleModule.setDeserializers(deserializers);
simpleModule.addSerializer(IEnum.class, new EnumsJacksonSerializer());
ObjectMapper objectMapper = builder.createXmlMapper(false).build();
objectMapper.registerModule(simpleModule);
return objectMapper;
}
/**
* 根据配置
* _classMappings映射关系为 com.example.common.properties.enums.IEnum -> com.example.common.jackson.EnumsJacksonDeserializer
* 传入类型type为 com.example.common.properties.enums.Status
* 重写遍历传入类型接口列表, 取出接口对应的反序列化器,实现面向接口的枚举反序列化
*/
public static class SimpleDeserializersWrapper extends SimpleDeserializers{
@Override
public JsonDeserializer<?> findEnumDeserializer(Class<?> type, DeserializationConfig config, BeanDescription beanDesc) throws JsonMappingException {
JsonDeserializer<?> deserializer = super.findEnumDeserializer(type, config, beanDesc);
if (deserializer != null) {
return deserializer;
}
//找出接口对应的反序列化器
for (Class<?> typeInterface : type.getInterfaces()) {
deserializer = this._classMappings.get(new ClassKey(typeInterface));
if (deserializer != null) {
return deserializer;
}
}
return null;
}
}
}
序列化时 SimpleSerializers$_findInterfaceMapping(Class<?> cls, ClassKey key) 方法会在 直接映射的序列化器没有的情况下,查询接口对应的序列化器
定义mybatis类型处理器
package com.example.common.properties.enums;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedTypes;
import org.apache.ibatis.type.TypeHandler;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
@MappedTypes({IEnum.class})
public class EnumsTypeHandler<T extends IEnum> implements TypeHandler<T> {
private T t;
@Override
public void setParameter(PreparedStatement statement, int i, T t, JdbcType jdbcType) throws SQLException {
this.t = t;
statement.setString(i, t.value());
}
@Override
public T getResult(ResultSet resultSet, String s) throws SQLException {
return (T) IEnum.codeOf(t.getClass(), resultSet.getString(s));
}
@Override
public T getResult(ResultSet resultSet, int i) throws SQLException {
return (T) IEnum.codeOf(t.getClass(), resultSet.getString(i));
}
@Override
public T getResult(CallableStatement statement, int i) throws SQLException {
return (T) IEnum.codeOf(t.getClass(), statement.getString(i));
}
}
配置mybatis类型处理器
mybatis:
type-handlers-package: com.example.common.properties.enums