Java非Int枚举JSON序列化和反序列化

Java枚举值默认是Integer类型的,但是我们经常会用到非数字类型值,例如:字符串。JSON序列化时,通常会使用枚举的序号作为值,FastJSON2可以通过JSONField来实现用名称作为值。

  public enum Color{      
        Red("red"),      
        Green("green"),
        Yellow("yellow"),
        Blue("blue");
        private String value;
        
        Color(String value) {
            this.value = value;
        }
        
        public String getValue() {
            return this.value;
        }
    }
    
    @Data
    public class Car{
        @JSONField(serializeFeatures = JSONWriter.Feature.WriteEnumsUsingName)
        private Color color;
        private String mode;
    }

如果将JSON反序列化就比较麻烦,例如一下JSON。

{
  "color":"yellow",
  "mode":"modelY"
}

如果项目中有多个这样的枚举类处理很麻烦。这里做了一个尝试,让枚举类实现EnumWithValue接口,在FastJSON公共配置统一设置序列和反序列化方法。

public interface EnumWithValue <T>{
    T getValue();
}

public enum Color implements EnumWithValue<String>{      
        Red("red"),      
        Green("green"),
        Yellow("yellow"),
        Blue("blue");
        private String value;
        
        Color(String value) {
            this.value = value;
        }        
        public String getValue() {
            return this.value;
        }
    }
    
    @Data
    public class Car{    
        //这里不需要用JSONField标注 
        private Color color;
        private String mode;
    }

这里使用了一个第三方的组件io.github.classgraph,扫描EnumWithValue的实现类,FastJSON2全局配置为每个实现类注册了objectReaderProvider和objectWriterProvider。

  • ClassScanner 对io.github.classgraph进行了简单封装,方便获取EnumWithValue的实现类;注意为了提高扫描的效率,需要限定下扫描包。

  • io.github.classgraph的maven依赖

 <dependency>
    <groupId>io.github.classgraph</groupId>
    <artifactId>classgraph</artifactId>
    <version>4.8.177</version>
 </dependency>
public class ClassScanner {
    private String[] packages;
    private ScanResult scanResult;

    public ClassScanner packages(String... packages) {
        this.packages = packages;
        return this;
    }
    public ClassScanner packages() {
        this.packages = new String[]{"com.xxx.bbb"};
        return this;
    }
    public ClassScanner scan() {
        this.scanResult = new ClassGraph()
                .enableClassInfo()
                .acceptPackages(packages)
                .scan();
        return this;
    }
    public List<Class<?>> getImplementing(Class<?> mClass) {
        if (this.scanResult == null) {
            this.scan();
        }

        ClassInfoList classInfos = scanResult.getClassesImplementing(mClass);
        List<Class<?>> list = new ArrayList<>();
        for (ClassInfo classInfo : classInfos) {
            try {
                Class<?> tClass = Class.forName(classInfo.getName());
                list.add(tClass);
            } catch (ClassNotFoundException e) {
                throw new RuntimeException(e);
            }
        }
        return list;
    }
    public void forEachImplementing(Class<?> mClass, Consumer<Class<?>> consumer) {
        List<Class<?>> list = getImplementing(mClass);
        for (Class<?> item : list) {
            consumer.accept(item);
        }
    }
    public static ClassScanner of() {
        return new ClassScanner().packages();
    }
    public static ClassScanner of(String... packages) {
        return new ClassScanner().packages(packages);
    }
}

public class FastJSON {
    public static final JSONWriter.Featu
    re[] WRITE_FEATURES = new JSONWriter.Feature[]{
            JSONWriter.Feature.WriteNullStringAsEmpty,
            JSONWriter.Feature.WriteNullListAsEmpty,
            JSONWriter.Feature.WriteNulls,
            JSONWriter.Feature.MapSortField,
            JSONWriter.Feature.WriteMapNullValue};
    public static long WRITE_FEATURES_MASK = 0L;

    static {
        WRITE_FEATURES_MASK = 0L;
        for (JSONWriter.Feature feature : WRITE_FEATURES) {
            WRITE_FEATURES_MASK |= feature.mask;
        }
        registerEnumValue();
    }

    public static FastJsonConfig getDefaultFastConfig() {
        FastJsonConfig fastJsonConfig = new FastJsonConfig();
        fastJsonConfig.setCharset(Charset.forName("utf8"));
        fastJsonConfig.setWriterFeatures(WRITE_FEATURES);
        return fastJsonConfig;
    }

    public static <T> T parseObject(String text, Class<T> objectClass) {
        return JSON.parseObject(text, objectClass);
    }

    public static String toJSONString(Object obj) {
        return JSON.toJSONString(obj, WRITE_FEATURES);
    }

    private static void registerEnumValue() {
        ObjectReaderProvider objectReaderProvider = JSONFactory.getDefaultObjectReaderProvider();
        ObjectWriterProvider objectWriterProvider = JSONFactory.getDefaultObjectWriterProvider();

        ClassScanner.of().forEachImplementing(EnumWithValue.class, aClass -> {
            objectReaderProvider.registerIfAbsent(aClass, (jsonReader, type, o, l) -> {
                EnumWithValue[] items = (EnumWithValue[]) aClass.getEnumConstants();
                Object value = jsonReader.readAny();
                EnumWithValue matched = Arrays.stream(items).filter(x -> x.getValue().equals(value)).findFirst().orElse(null);
                return matched != null ? matched : null;
            });
            objectWriterProvider.register(aClass, (jsonWriter, object, fieldName, fieldType, features) -> {
                EnumWithValue value = (EnumWithValue) object;
                jsonWriter.writeAny(value.getValue());
            });
        });
    }
}

这个方案看似有点麻烦,但只需要在定义枚举时,实现EnumWithValue接口即可。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

八爪虎

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值