zoukankan      html  css  js  c++  java
  • 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);

      }无锡人流多少钱 http://www.bhnfkyy.com/

      //(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。

  • 相关阅读:
    redis 基本指令
    php 魔术变量
    php 常用函数总结
    linux 命令——3 pwd (转)
    linux 命令——2 cd (转)
    linux 命令——ls
    ffmeg过滤器介绍[转]
    最简单的基于FFMPEG的转码程序 —— 分析
    ffmpga结构体和常用函数(总结)
    leetcode--3
  • 原文地址:https://www.cnblogs.com/djw12333/p/11156187.html
Copyright © 2011-2022 走看看