记录一次源码扩展案列——FastJson自定义反序列化值修改器ValueMutator


背景:曾经遇到一个很麻烦的事情,就是一个json串中有很多占位符,需要替换成特定文案。如果将json转换成对象后,在一个一个属性去转换的话就出出现很多冗余代码,不美观也不是很实用。

而且也不能提前在json串中替换,因为替换的文案会因为某些变量发生改变。就比如国际化,在中文的时候应该是"你好",而在英文的时候要出现"Hello"。

所以我想到一个方法,为什么不能再json反序列化的时候,把这些都做好呢?

以下的代码介绍的是,我自己扩展的一点点fastjson代码,增加了在反序列化的时候可以对所有的值进行修改的方案。

注意:这个方案会对fastjson反序列化的速度有一定的影响,我只是用来做配置的反序列化,完成后将反序列化的东西缓存起来使用。

使用方式有两种

一种是直接通过 @JsonDeserializer 注解的valueMutators属性注入这种方式有个缺陷,你的修改器必须有无参构造函数的 

@JsonDeserializer(valueMutators = {CoustomizeValueMutator.class})  
@Getter  
@Setter  
public class User { private String name; ... } 

第二种方式是通过直接创建的方式,使用反序列化工具,这种方式支持有参构造函数。

        CoustomizeValueMutator zhCoustomizeValueMutator = new CoustomizeValueMutator(zh);  
        User user = CustomizeJSON.parseObject(userStr, User.class, zhCoustomizeValueMutator);

 

下面先展示一下使用效果,测试代码如下:

import com.alibaba.fastjson.parser.deserializer.CustomizeJSON;
import com.raiden.model.*; import org.junit.jupiter.api.Test; import java.util.*; /** * @创建人:Raiden * @Descriotion: * @Date:Created in 22:39 2020/1/28 * @Modified By: */ public class AppTest { @Test public void testFastJosn() throws Throwable { String userStr = "{\n" + "\t\"id\":\"I18nKey:20200411001\",\n" + "\t\"a\":\"I18nKey:张三\",\n" + "\t\"student\":\"I18nKey:高三三班\",\n" + "\t\"contents\":[\"I18nKey:1\",\"I18nKey:2\"]\n" + "}"; Map<String, String> en = new HashMap<>(); en.put("3", "zhangsan"); en.put("4", "20200411001"); en.put("5", "Class three in grade three"); en.put("1", "Hello"); en.put("2", "Welcome home"); Map<String, String> zh = new HashMap<>(); zh.put("3", "张三"); zh.put("4", "20200411001"); zh.put("5", "高三三班"); zh.put("1", "你好"); zh.put("2", "欢迎回家"); CoustomizeValueMutator zhCoustomizeValueMutator = new CoustomizeValueMutator(zh); User user = CustomizeJSON.parseObject(userStr, User.class, zhCoustomizeValueMutator); System.err.println(user); String string = "{\n" + "\t\"users\": [{\n" + "\t\t\"id\": \"I18nKey:4\",\n" + "\t\t\"a\": \"I18nKey:3\",\n" + "\t\t\"student\": \"I18nKey:5\",\n" + "\t\t\"url\": \"www.baidu.com\",\n" + "\t\t\"contents\": [\"I18nKey:1\", \"I18nKey:2\"]\n" + "\t}],\n" + "\t\"memberId\":\"2020\"\n" + "}"; CoustomizeValueMutator enCoustomizeValueMutator = new CoustomizeValueMutator(en); Administration administration = CustomizeJSON.parseObject(string, Administration.class, enCoustomizeValueMutator); System.err.println(administration); } }

运行效果:

 下面是测试模型代码:

import com.alibaba.fastjson.parser.deserializer.JsonDeserializer;
import com.raiden.CoustomizeValueMutator; import lombok.Getter; import lombok.Setter; import java.util.List; /** * @创建人:Raiden * @Descriotion: * @Date:Created in 23:56 2020/4/17 * @Modified By: */ @JsonDeserializer @Getter @Setter public class Administration { private List<User> users; private String memberId; @Override public String toString() { return "Administration{" + "users=" + users + ", memberId='" + memberId + '\'' + '}'; } }
import com.alibaba.fastjson.parser.deserializer.JsonDeserializer;
import lombok.Getter; import lombok.Setter; import java.util.List; /** * @创建人:Raiden * @Descriotion: * @Date:Created in 15:53 2020/3/21 * @Modified By: */ @JsonDeserializer @Getter @Setter public class User { private String name; private String id; private String student; private List<String> contents; private String url; @Override public String toString() { return "User{" + "name='" + name + '\'' + ", id='" + id + '\'' + ", student='" + student + '\'' + ", contents='" + contents.toString() + '\'' + ", url='" + url + '\'' + '}'; } }

自定义的反序列化值修改器:

import com.alibaba.fastjson.parser.deserializer.DeserializerValueMutator;

import java.lang.annotation.Annotation; import java.util.ArrayList; import java.util.List; import java.util.Map; /** * @创建人:Raiden * @Descriotion: * @Date:Created in 22:15 2020/5/1 * @Modified By: */ public class CoustomizeValueMutator implements DeserializerValueMutator { private Map<String, String> dataSource; public CoustomizeValueMutator(Map<String, String> dataSource){ this.dataSource = dataSource; } @Override public Object process(Object object, Annotation[] annotations, String name, Object value) { if (value instanceof List){ List list = new ArrayList(); for (Object o : (List) value){ if (!(o instanceof String)){ return value; } list.add(DeserializerUtils.deserializer(o, dataSource)); } return list; } return DeserializerUtils.deserializer(value, dataSource); } }

一些工具类和静态资源类:

/**
 * @创建人:Raiden
 * @Descriotion:
 * @Date:Created in 23:00 2020/4/17
 * @Modified By:
 */
public class CustomizeStaticConfig {
    public static final String I18N_KEY = "I18nKey:"; }
import org.apache.commons.lang3.StringUtils;

import java.util.Map; /** * @创建人:Raiden * @Descriotion: * @Date:Created in 0:15 2020/4/18 * @Modified By: */ public final class DeserializerUtils { public static final Object deserializer(Object value, Map<String, String> languageConfig){ String result = null; if (value.getClass() == String.class && StringUtils.contains((result = ((String) value).trim()), CustomizeStaticConfig.I18N_KEY)){ int indexOf = result.indexOf(CustomizeStaticConfig.I18N_KEY) + CustomizeStaticConfig.I18N_KEY.length(); String key = StringUtils.substring(result, indexOf); return languageConfig.getOrDefault(key, result); } return value; } }

 下面给出的是扩展的关键代码。

首先是自定义解析配置类,这个类是核心。这个类继承了 com.alibaba.fastjson.parser.ParserConfig 类。覆写了其两个核心方法。

方法一:

createFieldDeserializer(ParserConfig mapping, JavaBeanInfo beanInfo, FieldInfo fieldInfo) 创建一个属性反序列化处理类

该方法的修改,是将源码中的 ArrayListTypeFieldDeserializer 替换成 我们自定义的 CustomizeArrayListTypeFieldDeserializer 处理器。

将源码中的 DefaultFieldDeserializer 替换成 我们自定义的 CustomizeDefaultFieldDeserializer 处理器

方法二:

createJavaBeanDeserializer(Class<?> clazz, Type type)  创建一个 JavaBean 反序列化处理器

新增判断逻辑,如果要反序列化的类上存在 @JsonDeserializer 标识注解,返回包含自定义配置类的 JavaBeanDeserializer。

import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson.parser.ParserConfig; import com.alibaba.fastjson.util.FieldInfo; import com.alibaba.fastjson.util.JavaBeanInfo; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.List; /** * @创建人:Raiden * @Descriotion: * @Date:Created in 21:52 2020/4/17 * @Modified By: 自定义fastjson 解析配置类 这个类是核心 */ public class CustomizeParserConfig extends ParserConfig { /** * 值修改器数组 可以将类修改器放入其中使用 */ private DeserializerValueMutator[] valueMutators; public CustomizeParserConfig(){ } /** * 有参构造方法 可以通过该方法 将类修改器放入其中 * @param valueMutators */ public CustomizeParserConfig(DeserializerValueMutator... valueMutators){ super(); this.valueMutators = valueMutators; } /** * 创建一个属性反序列化处理类 * @param mapping * @param beanInfo * @param fieldInfo * @return */ @Override public FieldDeserializer createFieldDeserializer(ParserConfig mapping, // JavaBeanInfo beanInfo, //  FieldInfo fieldInfo) { //获取要反序列化的model 的class Class<?> clazz = beanInfo.clazz; //获取要反序列化属性的 class Class<?> fieldClass = fieldInfo.fieldClass; Class<?> deserializeUsing = null; JSONField annotation = fieldInfo.getAnnotation(); if (annotation != null) { deserializeUsing = annotation.deserializeUsing(); if (deserializeUsing == Void.class) { deserializeUsing = null; } } if (deserializeUsing == null && (fieldClass == List.class || fieldClass == ArrayList.class)) { //将源码中的 ArrayListTypeFieldDeserializer 替换成 我们自定义的 CustomizeArrayListTypeFieldDeserializer 处理器 return new CustomizeArrayListTypeFieldDeserializer(clazz, fieldInfo, valueMutators); } //将源码中的 DefaultFieldDeserializer 替换成 我们自定义的 CustomizeDefaultFieldDeserializer 处理器 return new CustomizeDefaultFieldDeserializer(mapping, clazz, fieldInfo, valueMutators); } /** * 创建一个 javaBean 反序列化处理器 * @param clazz * @param type * @return */ @Override public ObjectDeserializer createJavaBeanDeserializer(Class<?> clazz, Type type) { //获取要反序列化类上的标识注解 JsonDeserializer jsonDeserializer = clazz.getAnnotation(JsonDeserializer.class); //如果不存在就走原逻辑 if (jsonDeserializer != null){ //获取注解中的反序列化值处理器 Class<? extends DeserializerValueMutator>[] classes = jsonDeserializer.valueMutators(); if (classes != null && classes.length > 0){ DeserializerValueMutator[] mutators = new DeserializerValueMutator[classes.length]; int size = 0; for (Class<? extends DeserializerValueMutator> c : classes) { try { DeserializerValueMutator mutator = c.newInstance(); mutators[size] = mutator; size++; } catch (Exception e) { //如果创建失败了就忽略掉这次错误  } } if (size > 0){ //判断原来是否有值 如果有 就合并成一组 if (valueMutators != null){ DeserializerValueMutator[] newValueMutators = new DeserializerValueMutator[size + valueMutators.length]; System.arraycopy(valueMutators, 0, newValueMutators, 0, valueMutators.length); System.arraycopy(mutators, 0, newValueMutators, valueMutators.length, size); this.valueMutators = newValueMutators; }else { this.valueMutators = new DeserializerValueMutator[size]; System.arraycopy(mutators, 0, valueMutators, 0, size); } } } if (valueMutators != null){ return new JavaBeanDeserializer(this, clazz); } } return super.createJavaBeanDeserializer(clazz, type); } }

 CustomizeDefaultFieldDeserializer 类继承了 DefaultFieldDeserializer 类在构造方法中新增了参数 valueMutators(值修改器数组)

并在 public void setValue(Object object, Object value) 方法中新增了逻辑如果值修改器数组中存在值修改器,就遍历所有的修改器,

依次调用修改器的 process方法修改值。

import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.parser.ParserConfig;
import com.alibaba.fastjson.util.FieldInfo;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

/**
 * @创建人:Raiden
 * @Descriotion:
 * @Date:Created in 0:13 2020/4/18
 * @Modified By: 替代fastjson中 对象反序列化处理类
 */
public class CustomizeDefaultFieldDeserializer extends DefaultFieldDeserializer {

    private DeserializerValueMutator[] valueMutators;

    public CustomizeDefaultFieldDeserializer(ParserConfig config, Class<?> clazz, FieldInfo fieldInfo,DeserializerValueMutator[] valueMutators) {
        super(config, clazz, fieldInfo);
        this.valueMutators = valueMutators;
    }

    public void setValue(Object object, Object value) {
        if (value == null //
                && fieldInfo.fieldClass.isPrimitive()) {
            return;
        } else if (fieldInfo.fieldClass == String.class
                && fieldInfo.format != null
                && fieldInfo.format.equals("trim")){
            value = ((String) value).trim();
        }
        try {
            /**
             * 如果值修改器数组中存在值修改器实例,就遍历该数组,依次调用所有的修改器的 process方法
             */
            if (valueMutators != null && valueMutators.length > 0){
                for (DeserializerValueMutator mutator : valueMutators){
                    value = mutator.process(object,fieldInfo.field.getAnnotations(), fieldInfo.name, value);
                }
            }
            Method method = fieldInfo.method;
            if (method != null) {
                if (fieldInfo.getOnly) {
                    if (fieldInfo.fieldClass == AtomicInteger.class) {
                        AtomicInteger atomic = (AtomicInteger) method.invoke(object);
                        if (atomic != null) {
                            atomic.set(((AtomicInteger) value).get());
                        }
                    } else if (fieldInfo.fieldClass == AtomicLong.class) {
                        AtomicLong atomic = (AtomicLong) method.invoke(object);
                        if (atomic != null) {
                            atomic.set(((AtomicLong) value).get());
                        }
                    } else if (fieldInfo.fieldClass == AtomicBoolean.class) {
                        AtomicBoolean atomic = (AtomicBoolean) method.invoke(object);
                        if (atomic != null) {
                            atomic.set(((AtomicBoolean) value).get());
                        }
                    } else if (Map.class.isAssignableFrom(method.getReturnType())) {
                        Map map = (Map) method.invoke(object);
                        if (map != null) {
                            if (map == Collections.emptyMap()
                                    || map.getClass().getName().startsWith("java.util.Collections$Unmodifiable")) {
                                // skip
                                return;
                            }

                            map.putAll((Map) value);
                        }
                    } else {
                        Collection collection = (Collection) method.invoke(object);
                        if (collection != null && value != null) {
                            if (collection == Collections.emptySet()
                                    || collection == Collections.emptyList()
                                    || collection.getClass().getName().startsWith("java.util.Collections$Unmodifiable")) {
                                // skip
                                return;
                            }

                            collection.clear();
                            collection.addAll((Collection) value);
                        }
                    }
                } else {
                    method.invoke(object, value);
                }
            } else {
                final Field field = fieldInfo.field;

                if (fieldInfo.getOnly) {
                    if (fieldInfo.fieldClass == AtomicInteger.class) {
                        AtomicInteger atomic = (AtomicInteger) field.get(object);
                        if (atomic != null) {
                            atomic.set(((AtomicInteger) value).get());
                        }
                    } else if (fieldInfo.fieldClass == AtomicLong.class) {
                        AtomicLong atomic = (AtomicLong) field.get(object);
                        if (atomic != null) {
                            atomic.set(((AtomicLong) value).get());
                        }
                    } else if (fieldInfo.fieldClass == AtomicBoolean.class) {
                        AtomicBoolean atomic = (AtomicBoolean) field.get(object);
                        if (atomic != null) {
                            atomic.set(((AtomicBoolean) value).get());
                        }
                    } else if (Map.class.isAssignableFrom(fieldInfo.fieldClass)) {
                        Map map = (Map) field.get(object);
                        if (map != null) {
                            if (map == Collections.emptyMap()
                                    || map.getClass().getName().startsWith("java.util.Collections$Unmodifiable")) {
                                // skip
                                return;
                            }
                            map.putAll((Map) value);
                        }
                    } else {
                        Collection collection = (Collection) field.get(object);
                        if (collection != null && value != null) {
                            if (collection == Collections.emptySet()
                                    || collection == Collections.emptyList()
                                    || collection.getClass().getName().startsWith("java.util.Collections$Unmodifiable")) {
                                // skip
                                return;
                            }

                            collection.clear();
                            collection.addAll((Collection) value);
                        }
                    }
                } else {
                    if (field != null) {
                        field.set(object, value);
                    }
                }
            }
        } catch (Exception e) {
            throw new JSONException("set property error, " + clazz.getName() + "#" + fieldInfo.name, e);
        }
    }
}

类CustomizeArrayListTypeFieldDeserializer 和 类CustomizeDefaultFieldDeserializer 改动类似。

import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.parser.ParserConfig;
import com.alibaba.fastjson.util.FieldInfo;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

/**
 * @创建人:Raiden
 * @Descriotion:
 * @Date:Created in 0:13 2020/4/18
 * @Modified By: 替代fastjson中 对象反序列化处理类
 */
public class CustomizeDefaultFieldDeserializer extends DefaultFieldDeserializer {

    private DeserializerValueMutator[] valueMutators;

    public CustomizeDefaultFieldDeserializer(ParserConfig config, Class<?> clazz, FieldInfo fieldInfo,DeserializerValueMutator[] valueMutators) {
        super(config, clazz, fieldInfo);
        this.valueMutators = valueMutators;
    }

    public void setValue(Object object, Object value) {
        if (value == null //
                && fieldInfo.fieldClass.isPrimitive()) {
            return;
        } else if (fieldInfo.fieldClass == String.class
                && fieldInfo.format != null
                && fieldInfo.format.equals("trim")){
            value = ((String) value).trim();
        }
        try {
            /**
             * 如果值修改器数组中存在值修改器实例,就遍历该数组,依次调用所有的修改器的 process方法
             */
            if (valueMutators != null && valueMutators.length > 0){
                for (DeserializerValueMutator mutator : valueMutators){
                    value = mutator.process(object,fieldInfo.field.getAnnotations(), fieldInfo.name, value);
                }
            }
            Method method = fieldInfo.method;
            if (method != null) {
                if (fieldInfo.getOnly) {
                    if (fieldInfo.fieldClass == AtomicInteger.class) {
                        AtomicInteger atomic = (AtomicInteger) method.invoke(object);
                        if (atomic != null) {
                            atomic.set(((AtomicInteger) value).get());
                        }
                    } else if (fieldInfo.fieldClass == AtomicLong.class) {
                        AtomicLong atomic = (AtomicLong) method.invoke(object);
                        if (atomic != null) {
                            atomic.set(((AtomicLong) value).get());
                        }
                    } else if (fieldInfo.fieldClass == AtomicBoolean.class) {
                        AtomicBoolean atomic = (AtomicBoolean) method.invoke(object);
                        if (atomic != null) {
                            atomic.set(((AtomicBoolean) value).get());
                        }
                    } else if (Map.class.isAssignableFrom(method.getReturnType())) {
                        Map map = (Map) method.invoke(object);
                        if (map != null) {
                            if (map == Collections.emptyMap()
                                    || map.getClass().getName().startsWith("java.util.Collections$Unmodifiable")) {
                                // skip
                                return;
                            }

                            map.putAll((Map) value);
                        }
                    } else {
                        Collection collection = (Collection) method.invoke(object);
                        if (collection != null && value != null) {
                            if (collection == Collections.emptySet()
                                    || collection == Collections.emptyList()
                                    || collection.getClass().getName().startsWith("java.util.Collections$Unmodifiable")) {
                                // skip
                                return;
                            }

                            collection.clear();
                            collection.addAll((Collection) value);
                        }
                    }
                } else {
                    method.invoke(object, value);
                }
            } else {
                final Field field = fieldInfo.field;

                if (fieldInfo.getOnly) {
                    if (fieldInfo.fieldClass == AtomicInteger.class) {
                        AtomicInteger atomic = (AtomicInteger) field.get(object);
                        if (atomic != null) {
                            atomic.set(((AtomicInteger) value).get());
                        }
                    } else if (fieldInfo.fieldClass == AtomicLong.class) {
                        AtomicLong atomic = (AtomicLong) field.get(object);
                        if (atomic != null) {
                            atomic.set(((AtomicLong) value).get());
                        }
                    } else if (fieldInfo.fieldClass == AtomicBoolean.class) {
                        AtomicBoolean atomic = (AtomicBoolean) field.get(object);
                        if (atomic != null) {
                            atomic.set(((AtomicBoolean) value).get());
                        }
                    } else if (Map.class.isAssignableFrom(fieldInfo.fieldClass)) {
                        Map map = (Map) field.get(object);
                        if (map != null) {
                            if (map == Collections.emptyMap()
                                    || map.getClass().getName().startsWith("java.util.Collections$Unmodifiable")) {
                                // skip
                                return;
                            }
                            map.putAll((Map) value);
                        }
                    } else {
                        Collection collection = (Collection) field.get(object);
                        if (collection != null && value != null) {
                            if (collection == Collections.emptySet()
                                    || collection == Collections.emptyList()
                                    || collection.getClass().getName().startsWith("java.util.Collections$Unmodifiable")) {
                                // skip
                                return;
                            }

                            collection.clear();
                            collection.addAll((Collection) value);
                        }
                    }
                } else {
                    if (field != null) {
                        field.set(object, value);
                    }
                }
            }
        } catch (Exception e) {
            throw new JSONException("set property error, " + clazz.getName() + "#" + fieldInfo.name, e);
        }
    }
}

下面是值修改器接口定义:

import java.lang.annotation.Annotation;

/**
 * @创建人:Raiden
 * @Descriotion:
 * @Date:Created in 22:01 2020/5/1
 * @Modified By: 反序列化值修改器接口
 */
public interface DeserializerValueMutator {

    Object process(Object object, Annotation[] annotations, String name, Object value);
}

反序列化标识注解,只有用这个注解注释的类才会执行拓展的方法。

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @创建人:Raiden
 * @Descriotion:
 * @Date:Created in 22:25 2020/4/17
 * @Modified By: 反序列化值修改标识注解
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE })
public @interface JsonDeserializer {
    /**
     * 注意这里只能放无参构造函数的修改器 否则会创建失败
     * @return
     */
    Class<? extends DeserializerValueMutator>[] valueMutators() default {};
}

强化的JSON序列化工具类:

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.Feature;

import java.lang.reflect.Type;

/**
 * @创建人:Raiden
 * @Descriotion:
 * @Date:Created in 22:12 2020/5/1
 * @Modified By: 反序列化工具类
 */
public final class CustomizeJSON {

    public static <T> T parseObject(String input,Type clazz,DeserializerValueMutator... valueMutators) {
        return JSON.parseObject(input, clazz, new CustomizeParserConfig(valueMutators));
    }

    public static <T> T parseObject(String json, Type type,DeserializerValueMutator[] valueMutators, Feature... features) {
        return JSON.parseObject(json, type, new CustomizeParserConfig(valueMutators), features);
    }

    public static <T> T parseObject(String json, Type type,Feature... features) {
        return JSON.parseObject(json, type, new CustomizeParserConfig(), features);
    }

    public static <T> T parseObject(String json, Type type) {
        return JSON.parseObject(json, type, new CustomizeParserConfig());
    }
}

以上代码都可以在我的git中下载:https://github.com/RaidenXin/fastjson-deserializer.git

创作不易,如果转载请注明出处,小编在此感谢各位看官。

如果觉得有用,请看官们点个赞,谢谢。

 

如果有想学Redis的可以关注我的Redis文章系列:

小白也能看懂的REDIS教学基础篇——REDIS基础数据结构

小白也能看懂的REDIS教学基础篇——朋友面试被SKIPLIST跳跃表拦住了

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM