fastjson源码分析 (一):序列化

 fastJson是很常用的序列化工具,用了这么久一直想底层看一下它的设计,探究一下它序列化和反序列化效率高的秘密。现在从最基础的用法开始,一点点揭开fastJson神秘的面纱。(版本:1.2.50)

 实际工程里,最常用的就是序列化和反序列化:

ResultDO resultDO = new ResultDO();

String jsonStr = JSON.toJSONString(resultDO);

ResultDO resultDO2 = JSON.parseObject(jsonStr, new TypeReference() {});

一.序列化

    1.先从JSON.toJSONString开始看。跟进到底层,最后会调用一个基本方法:

  public static String toJSONString(Object object, // 被序列化的对象
                                      SerializeConfig config, // 序列化全局配置
                                      SerializeFilter[] filters, //序列化的过滤器 
                                      String dateFormat, //日期格式
                                      int defaultFeatures, // 默认序列化特性
                                      SerializerFeature... features //自定义的序列化特性) {
        SerializeWriter out = new SerializeWriter(null, defaultFeatures, features);

        try {
            JSONSerializer serializer = new JSONSerializer(out, config);
            
            if (dateFormat != null && dateFormat.length() != 0) {
                serializer.setDateFormat(dateFormat);
                serializer.config(SerializerFeature.WriteDateUseDateFormat, true);
            }

            if (filters != null) {
                for (SerializeFilter filter : filters) {
                    serializer.addFilter(filter);
                }
            }

            serializer.write(object);

            return out.toString();
        } finally {
            out.close();
        }
    }

  (1)一开始,会初始化一个SerializeWriter,然后用自定义的features覆盖defaultFeatures配置。

  (2)然后初始化一个JSONSerializer对象,序列化结果写入SerializeWriter的buffer属性中。序列化执行的时候,会根据config查找具体的序列化处理器去做处理。

  (3)然后是对日期格式和过滤器的判断。

   SerializerFeature的用法在另一片文章里面有介绍:https://mp.csdn.net/postedit/84296853

    SerializeFilter用法不再赘述,可以戳github:https://github.com/alibaba/fastjson/wiki/SerializeFilter

  2.进入到write方法:

 public final void write(Object object) {
        if (object == null) {
            out.writeNull();
            return;
        }

        Class clazz = object.getClass();
        ObjectSerializer writer = getObjectWriter(clazz);

        try {
            writer.write(this, object, null, null, 0);
        } catch (IOException e) {
            throw new JSONException(e.getMessage(), e);
        }
    }

   在这步有一个getObjectWriter的方法,根据序列化对象的class类型,得到对应的序列化器。这段代码比较长,但可以总结为几种类型:

(1)从指定的目录下META-INF/services/,用当前线程的类加载器去取实现AutowiredObjectSerializer的序列化器

(2)与第一种区别的地方在于加载器不同,此时尝试用加载JSON的classLoader

(3)当前这种是针对传进来的clazz的类型,去寻找对应的序列化器。
       这里都是常用的一些类型,比如Map,List,Collection,Date,enum,Iterator等等。还有JSON相关的一些,JSONAware,JSONSerializable,JSONStreamAware 。
       特殊处理,(a)java自带图形包java.awt (b)jdk8中的日期包、Optional、concurrent(c)oracle相关的类(d)springfox相关的类(e)guava框架中类

  (4) 代理类,包括cglib或者javassist动态代理,或是jdk自带的动态代理。

(5)自主创建序列化器,createJavaBeanSerializer,这个之后要重点描述

private ObjectSerializer getObjectWriter(Class clazz, boolean create) {
       //private final IdentityHashMap serializers; serializer是一个定义的缓存map,key是Type,这里存放Class类型。value是对象的序列化器
        ObjectSerializer writer = serializers.get(clazz);
        
       //下面是依次对不同的情况去取序列化器
        //1.从指定的目录下META-INF/services/,去取实现AutowiredObjectSerializer的序列化器
        if (writer == null) {
            try {
                final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
                for (Object o : ServiceLoader.load(AutowiredObjectSerializer.class, classLoader)) {
                    if (!(o instanceof AutowiredObjectSerializer)) {
                        continue;
                    }

                    AutowiredObjectSerializer autowired = (AutowiredObjectSerializer) o;
                    for (Type forType : autowired.getAutowiredFor()) {
                        //如果存在,都放到serializers缓存中
                        put(forType, autowired);
                    }
                }
            } catch (ClassCastException ex) {
                // skip
            }
            //尝试在缓存找序列化器
            writer = serializers.get(clazz);
        }
        //2.与第一种区别的地方在于加载器不同,此时尝试用加载JSON的classLoader。
        if (writer == null) {
            final ClassLoader classLoader = JSON.class.getClassLoader();
            if (classLoader != Thread.currentThread().getContextClassLoader()) {
                try {
                    for (Object o : ServiceLoader.load(AutowiredObjectSerializer.class, classLoader)) {

                        if (!(o instanceof AutowiredObjectSerializer)) {
                            continue;
                        }

                        AutowiredObjectSerializer autowired = (AutowiredObjectSerializer) o;
                        for (Type forType : autowired.getAutowiredFor()) {
                            put(forType, autowired);
                        }
                    }
                } catch (ClassCastException ex) {
                    // skip
                }

                writer = serializers.get(clazz);
            }
        }
       //3.当前这种是针对传进来的clazz的类型,去寻找对应的序列化器。
       //这里都是常用的一些类型,比如Map,List,Collection,Date,enum,Iterator等等。还有JSON相关的一些,JSONAware,JSONSerializable,JSONStreamAware 。
       //特殊处理,(1)java自带图形包java.awt (2)jdk8中的日期包、Optional、concurrent(3)oracle相关的类(4)springfox相关的类(5)guava框架中类
        if (writer == null) {
            String className = clazz.getName();
            Class superClass;

            if (Map.class.isAssignableFrom(clazz)) {
                put(clazz, writer = MapSerializer.instance);
            } else if (List.class.isAssignableFrom(clazz)) {
                put(clazz, writer = ListSerializer.instance);
            } else if (Collection.class.isAssignableFrom(clazz)) {
                put(clazz, writer = CollectionCodec.instance);
            } else if (Date.class.isAssignableFrom(clazz)) {
                put(clazz, writer = DateCodec.instance);
            } else if (JSONAware.class.isAssignableFrom(clazz)) {
                put(clazz, writer = JSONAwareSerializer.instance);
            } else if (JSONSerializable.class.isAssignableFrom(clazz)) {
                put(clazz, writer = JSONSerializableSerializer.instance);
            } else if (JSONStreamAware.class.isAssignableFrom(clazz)) {
                put(clazz, writer = MiscCodec.instance);
            } else if (clazz.isEnum()) {
                JSONType jsonType = TypeUtils.getAnnotation(clazz, JSONType.class);
                if (jsonType != null && jsonType.serializeEnumAsJavaBean()) {
                    put(clazz, writer = createJavaBeanSerializer(clazz));
                } else {
                    put(clazz, writer = EnumSerializer.instance);
                }
            } else if ((superClass = clazz.getSuperclass()) != null && superClass.isEnum()) {
                JSONType jsonType = TypeUtils.getAnnotation(superClass, JSONType.class);
                if (jsonType != null && jsonType.serializeEnumAsJavaBean()) {
                    put(clazz, writer = createJavaBeanSerializer(clazz));
                } else {
                    put(clazz, writer = EnumSerializer.instance);
                }
            } else if (clazz.isArray()) {
                Class componentType = clazz.getComponentType();
                ObjectSerializer compObjectSerializer = getObjectWriter(componentType);
                put(clazz, writer = new ArraySerializer(componentType, compObjectSerializer));
            } else if (Throwable.class.isAssignableFrom(clazz)) {
                SerializeBeanInfo beanInfo = TypeUtils.buildBeanInfo(clazz, null, propertyNamingStrategy);
                beanInfo.features |= SerializerFeature.WriteClassName.mask;
                put(clazz, writer = new JavaBeanSerializer(beanInfo));
            } else if (TimeZone.class.isAssignableFrom(clazz) || Map.Entry.class.isAssignableFrom(clazz)) {
                put(clazz, writer = MiscCodec.instance);
            } else if (Appendable.class.isAssignableFrom(clazz)) {
                put(clazz, writer = AppendableSerializer.instance);
            } else if (Charset.class.isAssignableFrom(clazz)) {
                put(clazz, writer = ToStringSerializer.instance);
            } else if (Enumeration.class.isAssignableFrom(clazz)) {
                put(clazz, writer = EnumerationSerializer.instance);
            } else if (Calendar.class.isAssignableFrom(clazz) //
                    || XMLGregorianCalendar.class.isAssignableFrom(clazz)) {
                put(clazz, writer = CalendarCodec.instance);
            } else if (Clob.class.isAssignableFrom(clazz)) {
                put(clazz, writer = ClobSeriliazer.instance);
            } else if (TypeUtils.isPath(clazz)) {
                put(clazz, writer = ToStringSerializer.instance);
            } else if (Iterator.class.isAssignableFrom(clazz)) {
                put(clazz, writer = MiscCodec.instance);
            } else if (org.w3c.dom.Node.class.isAssignableFrom(clazz)) {
                put(clazz, writer = MiscCodec.instance);
            } else {
                if (className.startsWith("java.awt.") //
                    && AwtCodec.support(clazz) //
                ) {
                    // awt
                    if (!awtError) {
                        try {
                            String[] names = new String[]{
                                    "java.awt.Color",
                                    "java.awt.Font",
                                    "java.awt.Point",
                                    "java.awt.Rectangle"
                            };
                            for (String name : names) {
                                if (name.equals(className)) {
                                    put(Class.forName(name), writer = AwtCodec.instance);
                                    return writer;
                                }
                            }
                        } catch (Throwable e) {
                            awtError = true;
                            // skip
                        }
                    }
                }
                
                // jdk8
                if ((!jdk8Error) //
                    && (className.startsWith("java.time.") //
                        || className.startsWith("java.util.Optional") //
                        || className.equals("java.util.concurrent.atomic.LongAdder")
                        || className.equals("java.util.concurrent.atomic.DoubleAdder")
                    )) {
                    try {
                        {
                            String[] names = new String[]{
                                    "java.time.LocalDateTime",
                                    "java.time.LocalDate",
                                    "java.time.LocalTime",
                                    "java.time.ZonedDateTime",
                                    "java.time.OffsetDateTime",
                                    "java.time.OffsetTime",
                                    "java.time.ZoneOffset",
                                    "java.time.ZoneRegion",
                                    "java.time.Period",
                                    "java.time.Duration",
                                    "java.time.Instant"
                            };
                            for (String name : names) {
                                if (name.equals(className)) {
                                    put(Class.forName(name), writer = Jdk8DateCodec.instance);
                                    return writer;
                                }
                            }
                        }
                        {
                            String[] names = new String[]{
                                    "java.util.Optional",
                                    "java.util.OptionalDouble",
                                    "java.util.OptionalInt",
                                    "java.util.OptionalLong"
                            };
                            for (String name : names) {
                                if (name.equals(className)) {
                                    put(Class.forName(name), writer = OptionalCodec.instance);
                                    return writer;
                                }
                            }
                        }
                        {
                            String[] names = new String[]{
                                    "java.util.concurrent.atomic.LongAdder",
                                    "java.util.concurrent.atomic.DoubleAdder"
                            };
                            for (String name : names) {
                                if (name.equals(className)) {
                                    put(Class.forName(name), writer = AdderSerializer.instance);
                                    return writer;
                                }
                            }
                        }
                    } catch (Throwable e) {
                        // skip
                        jdk8Error = true;
                    }
                }
                
                if ((!oracleJdbcError) //
                    && className.startsWith("oracle.sql.")) {
                    try {
                        String[] names = new String[] {
                                "oracle.sql.DATE",
                                "oracle.sql.TIMESTAMP"
                        };

                        for (String name : names) {
                            if (name.equals(className)) {
                                put(Class.forName(name), writer = DateCodec.instance);
                                return writer;
                            }
                        }
                    } catch (Throwable e) {
                        // skip
                        oracleJdbcError = true;
                    }
                }
                
                if ((!springfoxError) //
                    && className.equals("springfox.documentation.spring.web.json.Json")) {
                    try {
                        put(Class.forName("springfox.documentation.spring.web.json.Json"), //
                                writer = SwaggerJsonSerializer.instance);
                        return writer;
                    } catch (ClassNotFoundException e) {
                        // skip
                        springfoxError = true;
                    }
                }

                if ((!guavaError) //
                        && className.startsWith("com.google.common.collect.")) {
                    try {
                        String[] names = new String[] {
                                "com.google.common.collect.HashMultimap",
                                "com.google.common.collect.LinkedListMultimap",
                                "com.google.common.collect.ArrayListMultimap",
                                "com.google.common.collect.TreeMultimap"
                        };

                        for (String name : names) {
                            if (name.equals(className)) {
                                put(Class.forName(name), writer = GuavaCodec.instance);
                                return writer;
                            }
                        }
                    } catch (ClassNotFoundException e) {
                        // skip
                        guavaError = true;
                    }
                }

                if ((!jsonnullError) && className.equals("net.sf.json.JSONNull")) {
                    try {
                        put(Class.forName("net.sf.json.JSONNull"), writer = MiscCodec.instance);
                        return writer;
                    } catch (ClassNotFoundException e) {
                        // skip
                        jsonnullError = true;
                    }
                }
                //如果class实现唯一接口,并且接口包含注解,使用AnnotationSerializer序列化
                Class[] interfaces = clazz.getInterfaces();
                if (interfaces.length == 1 && interfaces[0].isAnnotation()) {
                    put(clazz, AnnotationSerializer.instance);
                    return AnnotationSerializer.instance;
                }
                //如果使用了cglib或者javassist动态代理
                if (TypeUtils.isProxy(clazz)) {
                    //得到父类并获取父类的序列化器
                    Class superClazz = clazz.getSuperclass();

                    ObjectSerializer superWriter = getObjectWriter(superClazz);
                    put(clazz, superWriter);
                    return superWriter;
                }
                //如果是jdk自带的动态代理
                if (Proxy.isProxyClass(clazz)) {
                    Class handlerClass = null;
                    //如果继承两个接口,取第二个接口做为handlerClass
                    if (interfaces.length == 2) {
                        handlerClass = interfaces[1];
                    } else {
                        for (Class proxiedInterface : interfaces) {
   //spring切面相关的接口,跳过                         if(proxiedInterface.getName().startsWith("org.springframework.aop.")) {
                                continue;
                            }
                            //如果除了aop的有多个接口,则跳出,并置handlerClass为null
                            if (handlerClass != null) {
                                handlerClass = null; // multi-matched
                                break;
                            }
                            handlerClass = proxiedInterface;
                        }
                    }
                    //handlerClass不为null,作为父类寻找序列化器,作为当前类的序列化器
                    if (handlerClass != null) {
                        ObjectSerializer superWriter = getObjectWriter(handlerClass);
                        put(clazz, superWriter);
                        return superWriter;
                    }
                }
                //如果开启,使用JavaBeanSerializer 序列化
                if (create) {
                    writer = createJavaBeanSerializer(clazz);
                    put(clazz, writer);
                }
            }

            if (writer == null) {
                writer = serializers.get(clazz);
            }
        }
        return writer;
    }

       当使用toJSONString()方法时,如果不添加参数,默认create时true。大部分时候,我们要序列化的对象都是自定义的对象,所以进入createJavaBeanSerializer方法中一探究竟:

 public final ObjectSerializer createJavaBeanSerializer(Class clazz) {
	    SerializeBeanInfo beanInfo = TypeUtils.buildBeanInfo(clazz, null, propertyNamingStrategy, fieldBased);
	    if (beanInfo.fields.length == 0 && Iterable.class.isAssignableFrom(clazz)) {
	        return MiscCodec.instance;
	    }

	    return createJavaBeanSerializer(beanInfo);
	}

   TypeUtils.buildBeanInfo会创建一个SerializeBeanInfo对象,看一下它的几个参数:

public static SerializeBeanInfo buildBeanInfo(Class beanType //
            , Map aliasMap //
            , PropertyNamingStrategy propertyNamingStrategy //
            , boolean fieldBased //
    ){
     ...   
}

(1)Class beanType :class对象类型

(2)Map aliasMap:序列化对象字段的map,配置的属性真正的名称。默认为null。

(3)PropertyNamingStrategy propertyNamingStrategy:命名方式,“驼峰式”等

(4)boolean fieldBased:判断走哪一种收集fieldInfo的方法

 理解完参数,再看下build的逻辑。代码比较长,我们拆开看:

(1)jsonType:

我们结合例子一起看一下,JSONType和JSONField都可以定制序列化,可以设置包含,忽略,也可以设置格式。

//@JSONType(ignores ={"id", "sex"}) 
//@JSONType(includes={"name","sex"}) 
public class User {

    @JSONField(name = "ID", ordinal = 3, serializeUsing = UserIDValueSerializer.class)
    private Long id;
    @JSONField(serialize = false)
    private String name;
    @JSONField(serialize = true, ordinal = 2)
    private String sex;

    @JSONField(deserialize = false)
    private String address;
    @JSONField(deserialize = true)
    private String phone;

    // 配置date序列化和反序列使用yyyyMMdd日期格式
    @JSONField(format = "yyyyMMdd", ordinal = 1)
    private Date date;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    //get and set ...
}
        //1.寻找当前class对象中,是否有JSONType注解
        //先查询当前类,如果没有,再查询元素上存在的所有注解,包括从父类继承的。  
        JSONType jsonType = TypeUtils.getAnnotation(beanType,JSONType.class);
        String[] orders = null;
        final int features;
        String typeName = null, typeKey = null;
        if(jsonType != null){
            //获取序列化的顺序
            orders = jsonType.orders();

            typeName = jsonType.typeName();
            if(typeName.length() == 0){
                typeName = null;
            }
            //获取命名类型,分为四种,以“personName”为例
            //(1)CamelCase(personName) (2)PascalCase(PersonName)(3)SnakeCase(person_name)(4)KebabCase(person-name)
            PropertyNamingStrategy jsonTypeNaming = jsonType.naming();
            //如果不是默认的驼峰式,就说明用户设置了name属性,覆盖传进来的propertyNamingStrategy参数
            if (jsonTypeNaming != PropertyNamingStrategy.CamelCase) {
                propertyNamingStrategy = jsonTypeNaming;
            }
            // 形成新的features值。这里的位运算存储很有意思,是一种很高效的设计。
            features = SerializerFeature.of(jsonType.serialzeFeatures());
            //循环向上寻找父类,如果找到有父类设置了typeKey,赋给变量存下来
            for(Class supperClass = beanType.getSuperclass()
                ; supperClass != null && supperClass != Object.class
                    ; supperClass = supperClass.getSuperclass()){
                JSONType superJsonType = TypeUtils.getAnnotation(supperClass,JSONType.class);
                if(superJsonType == null){
                    break;
                }
                typeKey = superJsonType.typeKey();
                if(typeKey.length() != 0){
                    break;
                }
            }
            //遍历寻找当前类实现的接口,如果找到有父类设置了typeKey,赋给变量存下来
            for(Class interfaceClass : beanType.getInterfaces()){
                JSONType superJsonType = TypeUtils.getAnnotation(interfaceClass,JSONType.class);
                if(superJsonType != null){
                    typeKey = superJsonType.typeKey();
                    if(typeKey.length() != 0){
                        break;
                    }
                }
            }

            if(typeKey != null && typeKey.length() == 0){
                typeKey = null;
            }
        } else{
            features = 0;
        }

   聊一下SerializerFeature这个枚举类:

 SerializerFeature(){
        mask = (1 << ordinal());
    }

   这个枚举类是把所有feature按照顺序,位偏移计算后,得到一个mask,作为当前feature的标记值。ordinal()的取值是0~Integer.MAX_VALUE。所以第一个枚举类的值是 1,第二个是"10",第三个是"100",依次类推,可以存31个枚举值。

  所以每一位代表一个特征值,1是有,0是无。一个int数就可以表示当前设置了哪些特征值。

  这种设计思路对项目开发是很有帮助的,毕竟位运算是最高效的运算。

 Q:算上@Deprecated的,已经有30个特征值了,万一以后多加了特征值该怎么存储呢,直接把mask改为long型么?

 

 接着看具体的解析:

这里分为两种方式:(1)computeGettersWithFieldBase (2)computeGetters  

      
        // fieldName,field ,先生成fieldName的快照,减少之后的findField的轮询
        Map fieldCacheMap = new HashMap();
        ParserConfig.parserAllFieldToCache(beanType, fieldCacheMap);
        //根据fieldBased判断走哪一个getter方法,默认是false。
        List fieldInfoList = fieldBased
                ? computeGettersWithFieldBase(beanType, aliasMap, false, propertyNamingStrategy) //
                : computeGetters(beanType, jsonType, aliasMap, fieldCacheMap, false, propertyNamingStrategy);
        FieldInfo[] fields = new FieldInfo[fieldInfoList.size()];
        fieldInfoList.toArray(fields);
        FieldInfo[] sortedFields;
        List sortedFieldList;
        if(orders != null && orders.length != 0){
            sortedFieldList = fieldBased
                    ? computeGettersWithFieldBase(beanType, aliasMap, true, propertyNamingStrategy) //
                    : computeGetters(beanType, jsonType, aliasMap, fieldCacheMap, true, propertyNamingStrategy);
        } else{
            sortedFieldList = new ArrayList(fieldInfoList);
            Collections.sort(sortedFieldList);
        }
        sortedFields = new FieldInfo[sortedFieldList.size()];
        sortedFieldList.toArray(sortedFields);
        if(Arrays.equals(sortedFields, fields)){
            sortedFields = fields;
        }
        return new SerializeBeanInfo(beanType, jsonType, typeName, typeKey, features, fields, sortedFields);

  先看一下computeGettersWithFieldBase方法:

 public static List computeGettersWithFieldBase(
            Class clazz, //
            Map aliasMap, //
            boolean sorted, //
            PropertyNamingStrategy propertyNamingStrategy){
        Map fieldInfoMap = new LinkedHashMap();
        for(Class currentClass = clazz; currentClass != null; currentClass = currentClass.getSuperclass()){
            Field[] fields = currentClass.getDeclaredFields();
            computeFields(currentClass, aliasMap, propertyNamingStrategy, fieldInfoMap, fields);
        }
        return getFieldInfos(clazz, sorted, fieldInfoMap);
    }

 配合上面的例子,来看computeFields方法是如何一步步解析的:

   private static void computeFields(
            Class clazz, //
            Map aliasMap, //
            PropertyNamingStrategy propertyNamingStrategy, //
            Map fieldInfoMap, //
            Field[] fields){
        for(Field field : fields){
            //获取属性的修饰符。如果是静态变量,则跳过,不放在fieldInfoMap中
            if(Modifier.isStatic(field.getModifiers())){
                continue;
            }
            //读取JSONField注解,解析序列化的定制化配置
            JSONField fieldAnnotation = field.getAnnotation(JSONField.class);
            //不小心发现一个拼写错误,“serialzeFeatures”。FieldInfo类里面的属性也是这个。强迫症患者。
            int ordinal = 0, serialzeFeatures = 0, parserFeatures = 0;
            String propertyName = field.getName();
            String label = null;
            if(fieldAnnotation != null){
                //依次解析注解的serialize、ordinal、serialzeFeatures、parserFeatures、propertyName、label属性,这个例子里可以看到
                if(!fieldAnnotation.serialize()){
                    continue;
                }
                ordinal = fieldAnnotation.ordinal();
                serialzeFeatures = SerializerFeature.of(fieldAnnotation.serialzeFeatures());
                parserFeatures = Feature.of(fieldAnnotation.parseFeatures());
                if(fieldAnnotation.name().length() != 0){
                    propertyName = fieldAnnotation.name();
                }
                if(fieldAnnotation.label().length() != 0){
                    label = fieldAnnotation.label();
                }
            }
            //如果传入的aliasMap不为null,就用别名。如果别名为null,就直接跳过
            //Q:aliasMap会存放所有属性的别名么?如果不是,等于null就跳过,那这个属性就被抛弃了,不会放到fieldInfoMap中。
            if(aliasMap != null){
                propertyName = aliasMap.get(propertyName);
                if(propertyName == null){
                    continue;
                }
            }
            //属性的命名策略,修改格式
            if(propertyNamingStrategy != null){
                propertyName = propertyNamingStrategy.translate(propertyName);
            }
            //生成FieldInfo,并放到map中
            if(!fieldInfoMap.containsKey(propertyName)){
                FieldInfo fieldInfo = new FieldInfo(propertyName, null, field, clazz, null, ordinal, serialzeFeatures, parserFeatures,
                        null, fieldAnnotation, label);
                fieldInfoMap.put(propertyName, fieldInfo);
            }
        }
    }

  再看一下 computeGetters方法:

 public static List computeGetters(Class clazz, //
                                                 JSONType jsonType, //
                                                 Map aliasMap, //
                                                 Map fieldCacheMap, //
                                                 boolean sorted, //
                                                 PropertyNamingStrategy propertyNamingStrategy //
    ){
        Map fieldInfoMap = new LinkedHashMap();
        boolean kotlin = TypeUtils.isKotlin(clazz);
        // for kotlin
        Constructor[] constructors = null;
        Annotation[][] paramAnnotationArrays = null;
        String[] paramNames = null;
        short[] paramNameMapping = null;
        Method[] methods = clazz.getMethods();
        for(Method method : methods){
            String methodName = method.getName();
            int ordinal = 0, serialzeFeatures = 0, parserFeatures = 0;
            String label = null;
            //对特殊情况的判断(序列化目标是寻找get方法)
            //(1)静态方法(2)返回类型是void(3)参数类型数组长度不是0.也就是存在参数(4)返回类类型是类加载器(5)groovy的MetaClass(6)异常处理getSuppressed(7)Kotlin类型
            if(Modifier.isStatic(method.getModifiers())){
                continue;
            }
            。。。
 
            /**
             *  如果在属性或者方法上存在JSONField注解,并且定制了name属性,不以类上的propertyNamingStrategy设置为准,以此字段的JSONField的name定制为准。
             */
            Boolean fieldAnnotationAndNameExists = false;
            //判断是否有JSONField注解
            JSONField annotation = method.getAnnotation(JSONField.class);
            if(annotation == null){
                annotation = getSuperMethodAnnotation(clazz, method);
            }
            //kotlin相关,不常用到
            if(annotation == null && kotlin){
               。。。
            }
            //如果有注解,读取注解中定义的name,feature等参数
            if(annotation != null){
                if(!annotation.serialize()){
                    continue;
                }
                ordinal = annotation.ordinal();
                serialzeFeatures = SerializerFeature.of(annotation.serialzeFeatures());
                parserFeatures = Feature.of(annotation.parseFeatures());
                if(annotation.name().length() != 0){
                    String propertyName = annotation.name();
                    if(aliasMap != null){
                        propertyName = aliasMap.get(propertyName);
                        if(propertyName == null){
                            continue;
                        }
                    }
                    FieldInfo fieldInfo = new FieldInfo(propertyName, method, null, clazz, null, ordinal,
                            serialzeFeatures, parserFeatures, annotation, null, label);
                    fieldInfoMap.put(propertyName, fieldInfo);
                    continue;
                }
                if(annotation.label().length() != 0){
                    label = annotation.label();
                }
            }
            //常用方法,判断方法是否以“get”开头
            if(methodName.startsWith("get")){
                 //排除特殊情况(1)长度<4(2)getClass (3)枚举类的getDeclaringClass
                if(methodName.length() < 4){
                    continue;
                }
                if(methodName.equals("getClass")){
                    continue;
                }
                if(methodName.equals("getDeclaringClass") && clazz.isEnum()){
                    continue;
                }
                char c3 = methodName.charAt(3);
                String propertyName;
                //开始解析get方法,判断get之后的第一个字符c3
                //1、如果c3是大写,判断compatibleWithJavaBean属性(默认为false),
                //如果为true,截取get后的字符串,如果前两位都是大写,则直接返回;其他情况,把首字母变小写返回。 
                //如果是false,直接把get后字符串的第一位变小写返回。
                //2.如果是'_','f'等特殊情况,按照各自规则截取。
                if(Character.isUpperCase(c3) //
                        || c3 > 512 // for unicode method name
                        ){
                    if(compatibleWithJavaBean){
                        propertyName = decapitalize(methodName.substring(3));
                    } else{
                        propertyName = Character.toLowerCase(methodName.charAt(3)) + methodName.substring(4);
                    }
                    //这里还有一个替换过程。还记得上面buildBeanInfo中生成的fieldCacheMap么,这里面存的是类得到的所有field。所以如果compatibleWithFieldName为true,代表按照field属性的大小写来,如果methodName的get方法之后的字符串在属性map里面,就用map中存好的属性。
                    propertyName = getPropertyNameByCompatibleFieldName(fieldCacheMap, methodName, propertyName, 3);
                } else if(c3 == '_'){
                    propertyName = methodName.substring(4);
                } else if(c3 == 'f'){
                    propertyName = methodName.substring(3);
                } else if(methodName.length() >= 5 && Character.isUpperCase(methodName.charAt(4))){
                    propertyName = decapitalize(methodName.substring(3));
                } else{
                    continue;
                }
                //判断JSONType注解的includes 和 ignores 属性,如果是忽略的,跳过这个方法的属性检测。提一下,这里的比较是区分大小写的equals,所以设置includes 和 ignores,最好看看它上述的解析规则,否则属性设置未必生效。
                boolean ignore = isJSONTypeIgnore(clazz, propertyName);
                if(ignore){
                    continue;
                }
                //假如bean的field很多的情况一下,轮询时将大大降低效率
                //假设现在得到的propertyName是“personName”,getFieldFromCache会从不同key尝试从fieldCacheMap获取field。(1)"_personName"(2)"m_personName"(3)"PersonName"(4) propertyName长度大于2且首字母小写,第二个字母大写的时候,忽略大小写从map中尝试获取。(不是很懂这个特殊逻辑)
                Field field = ParserConfig.getFieldFromCache(propertyName, fieldCacheMap);
                //如果还没获取到,且propertyName第二个字符是大写,再得到javaBeanCompatiblePropertyName,尝试从map中获取。
                if(field == null && propertyName.length() > 1){
                    char ch = propertyName.charAt(1);
                    if(ch >= 'A' && ch <= 'Z'){
                        String javaBeanCompatiblePropertyName = decapitalize(methodName.substring(3));
                        field = ParserConfig.getFieldFromCache(javaBeanCompatiblePropertyName, fieldCacheMap);
                    }
                }
                JSONField fieldAnnotation = null;
                //检测这个field是否有设置属性
                if(field != null){
                    fieldAnnotation = field.getAnnotation(JSONField.class);
                    if(fieldAnnotation != null){
                        if(!fieldAnnotation.serialize()){
                            continue;
                        }
                        ordinal = fieldAnnotation.ordinal();
                        serialzeFeatures = SerializerFeature.of(fieldAnnotation.serialzeFeatures());
                        parserFeatures = Feature.of(fieldAnnotation.parseFeatures());
                        if(fieldAnnotation.name().length() != 0){
                            fieldAnnotationAndNameExists = true;
                            propertyName = fieldAnnotation.name();
                            if(aliasMap != null){
                                propertyName = aliasMap.get(propertyName);
                                if(propertyName == null){
                                    continue;
                                }
                            }
                        }
                        if(fieldAnnotation.label().length() != 0){
                            label = fieldAnnotation.label();
                        }
                    }
                }
                //默认情况下,aliasMap为null
                if(aliasMap != null){
                    propertyName = aliasMap.get(propertyName);
                    if(propertyName == null){
                        continue;
                    }
                }
                //propertyNamingStrategy不为null,修改格式
                if(propertyNamingStrategy != null && !fieldAnnotationAndNameExists){
                    propertyName = propertyNamingStrategy.translate(propertyName);
                }
                FieldInfo fieldInfo = new FieldInfo(propertyName, method, field, clazz, null, ordinal, serialzeFeatures, parserFeatures,
                        annotation, fieldAnnotation, label);
                fieldInfoMap.put(propertyName, fieldInfo);
            }
            //如果是is开头的,是类似的逻辑。不再赘述
            if(methodName.startsWith("is")){
                。。。
            }
        }
        Field[] fields = clazz.getFields();
        //最后再调用computeFields方法  
        computeFields(clazz, aliasMap, propertyNamingStrategy, fieldInfoMap, fields);
        return getFieldInfos(clazz, sorted, fieldInfoMap);
    }

    小结一下computeGetters方法的逻辑:

 (1)对特殊情况的判断(序列化目标是寻找get方法)
     (a)静态方法

     (b)返回类型是void

     (c)参数类型数组长度不是0.也就是存在参数

     (d)返回类类型是类加载器

     (e)groovy的MetaClass

     (f)异常处理getSuppressed

     (g)Kotlin类型

  (2) check当前的method是否有JSONField注解,并判断是否是kotlin相关的类。 (JSONField可以设置在属性上,也可以设置在方法上。)

(3)“get”开头的解析。

    (a)排除特殊情况:长度<4;getClass ;枚举类的getDeclaringClass

    (b) 开始解析get方法,判断get之后的第一个字符c3。

               如果c3是大写,判断compatibleWithJavaBean属性(默认为false),如果为true,截取get后的字符串,如果前两位都       是大写,则直接返回;其他情况,把首字母变小写返回。 如果是false,直接把get后字符串的第一位变小写返回。如果是'_','f'等特殊情况,按照各自规则截取。

               这里还有一个替换过程。传进来的buildBeanInfo中生成的fieldCacheMap,这里面存的是类得到的所有field。所以如果compatibleWithFieldName为true,代表按照field属性的大小写来,如果methodName的get方法之后的字符串在属性map里面,就用map中存好的属性。

               fastJson在多处用了这种map,优化了查询的效率。                   

(4)对得到field中的JSONField注解做解析。

 

   到这里,SerializeBeanInfo的步骤就基本完成了,接下来就是正式的去生成序列化器的方法createJavaBeanSerializer:

在之前先提一下,fastjson内嵌了ASM框架来动态生成类,ASMClassLoader继承了java的类装载器ClassLoader。

public ObjectSerializer createJavaBeanSerializer(SerializeBeanInfo beanInfo) {
	    JSONType jsonType = beanInfo.jsonType;

        boolean asm = this.asm && !fieldBased;
	    //jsonType注解不为null
	    if (jsonType != null) {
            //jsonType中设置的序列化器属性,默认是Void.class
	        Class serializerClass = jsonType.serializer();
	        if (serializerClass != Void.class) {
	            try {
                    //如果是自己写的序列化器,继承了ObjectSerializer接口,直接返回用户设定的序列化器。
                    Object seralizer = serializerClass.newInstance();
                    if (seralizer instanceof ObjectSerializer) {
                        return (ObjectSerializer) seralizer;
                    }
                } catch (Throwable e) {
                    // skip
                }
	        }
	        //jsonType设定了asm可用属性。
	        if (jsonType.asm() == false) {
	            asm = false;
	        }
            
	        if (asm) {
                //check:如果设置了下面的一些属性,即使asm可用,也设置为不可用。    
                for (SerializerFeature feature : jsonType.serialzeFeatures()) {
                    if (SerializerFeature.WriteNonStringValueAsString == feature //
                            || SerializerFeature.WriteEnumUsingToString == feature //
                            || SerializerFeature.NotWriteDefaultValue == feature
                            || SerializerFeature.BrowserCompatible == feature) {
                        asm = false;
                        break;
                    }
                }
            }
            
            if (asm) {
                //check:如果设置了过滤器,asm也禁用 
                final Class[] filterClasses = jsonType.serialzeFilters();
                if (filterClasses.length != 0) {
                    asm = false;
                }
            }
        }

	    Class clazz = beanInfo.beanType;
        //如果bean是public的,直接用JavaBeanSerializer返回。
		if (!Modifier.isPublic(beanInfo.beanType.getModifiers())) {
			return new JavaBeanSerializer(beanInfo);
		}


        //(1)如果是类加载器在ASMClassLoader的外部(2)或者clazz就是 Serializable.class(3)clazz就是Object.class
		if (asm && asmFactory.classLoader.isExternalClass(clazz)
				|| clazz == Serializable.class || clazz == Object.class) {
			asm = false;
		}
        //不符合asm的命名规则
		if (asm && !ASMUtils.checkName(clazz.getSimpleName())) {
		    asm = false;
		}
        //接口    
		if (asm && beanInfo.beanType.isInterface()) {
		    asm = false;
        }
		
		if (asm) {
            //对每一个属性做check
    		for(FieldInfo fieldInfo : beanInfo.fields){
                Field field = fieldInfo.field;
                if (field != null && !field.getType().equals(fieldInfo.fieldClass)) {
                    asm = false;
                    break;
                }

                Method method = fieldInfo.method;
                if (method != null && !method.getReturnType().equals(fieldInfo.fieldClass)) {
                    asm = false;
                    break;
                }

    			JSONField annotation = fieldInfo.getAnnotation();
    			
    			if (annotation == null) {
    			    continue;
    			}

    			String format = annotation.format();
    			if (format.length() != 0) {
    			    if (fieldInfo.fieldClass == String.class && "trim".equals(format)) {

                    } else {
                        asm = false;
                        break;
                    }
                }

                if ((!ASMUtils.checkName(annotation.name())) //
                        || annotation.jsonDirect()
                        || annotation.serializeUsing() != Void.class
                        || annotation.unwrapped()
                        ) {
    				asm = false;
    				break;
    			}

                for (SerializerFeature feature : annotation.serialzeFeatures()) {
                    if (SerializerFeature.WriteNonStringValueAsString == feature //
                            || SerializerFeature.WriteEnumUsingToString == feature //
                            || SerializerFeature.NotWriteDefaultValue == feature
                            || SerializerFeature.BrowserCompatible == feature
                            || SerializerFeature.WriteClassName == feature) {
                        asm = false;
                        break;
                    }
                }

                if (TypeUtils.isAnnotationPresentOneToMany(method) || TypeUtils.isAnnotationPresentManyToMany(method)) {
    			    asm = false;
    			    break;
                }
    		}
		}
		
		if (asm) {
			try {
                ObjectSerializer asmSerializer = createASMSerializer(beanInfo);
                if (asmSerializer != null) {
                    return asmSerializer;
                }
            } catch (ClassNotFoundException ex) {
			    // skip
			} catch (ClassFormatError e) {
			    // skip
			} catch (ClassCastException e) {
			    // skip
            } catch (OutOfMemoryError e) {
			    if (e.getMessage().indexOf("Metaspace") != -1) {
			        throw e;
                }
                // skip
			} catch (Throwable e) {
				throw new JSONException("create asm serializer error, verson " + JSON.VERSION + ", class " + clazz, e);
			}
		}

		return new JavaBeanSerializer(beanInfo);
	}

两种得到序列化器的方法:(1)JavaBeanSerializer(2)createASMSerializer

使用asm的条件:

(1)JSONType注解设置了asm的属性为不可用

  (2)SerializerFeature设置某些序列化属性,WriteNonStringValueAsString、WriteEnumUsingToString、NotWriteDefaultValue、BrowserCompatible。

  (3)如果设置了过滤器,asm也禁用 。

  (4)该clazz为非public类

  (5) 该clazz的类加载器在ASMClassLoader的外部、clazz是Serializable.class或者Object.class

  (6)不符合asm的命名规则、bean是接口类型

  (7)对每一个field属性的check,如果不满足条件也禁用asm。

你可能感兴趣的:(java)