gson完全解读

##前言
网络请求框架一直没搞,这个东西一直是我的一个遗憾。最近用到这里我们好好的研究下,本篇博客主要研究一下gson相关的东西。
##正文
gson是什么:

A Java serialization/deserialization library to convert Java Objects into JSON and back 

发现看不懂,只能才懂大概意思是就是把java对象和JSON相互转化。这个库的简介貌似没说清楚我们继续读readme

Gson is a Java library that can be used to convert Java Objects into their JSON representation. It can also be used to convert a JSON string to an equivalent Java object. Gson can work with arbitrary Java objects including pre-existing objects that you do not have source-code of.

这句话就容易理解了,Gson是可以把java类转化成json的表示形式,也可以吧json字符串转换成java类。后面部分就是装逼的,大概意思是gson是可以转化任意java类,包括没有代码的实体类(主要是针对泛型,泛型在运行期之前不存在类型)。
好多人都会说道理我都懂,可是到底json是个什么鬼。百度百科有讲

JSON(JavaScript Object Notation, JS 对象简谱) 是一种轻量级的数据交换格式。它基于 ECMAScript (欧洲计算机协会制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率

这个括号把人给搞蒙了,什么鬼简谱,这种类比简直无法忍受啊!我们看的英文单词Notation的意思是指“记号,标记法”,真正的意思是javascrip 对象的记录方法。通俗的讲是记录一个对象的方法。这和java的序列化是一个目的,都是为了对象的传输和存储。
后半部分就好理解了,主要特性和历史。
特性:轻量级、简洁 清晰的层次机构。已于阅读编写,易于解析,占用网络少。
用途:数据交换(网络中后台和客户端的通讯。本地存储数据库中可以直接存这东东)
历史:略
json是一种对象的标记方法,最终记录在哪里?是什么格式呢?因为网络更容易存储字符串,所以呢,最终json是通过字符串来记录的。

也就是说json是一种特定的语法的字符串,可以转换成JS的类,也可以通过JS生成Json字符串。

###json是什么语法
因为方法是没办法传输的,类只记录内容才有意义,所以这里只存在数据类型和变量值,变量名也不能少。数据类型这里基本数据类型都完全支持,另外还有组合类型,数组和类。
举个简答的例子

 {"name": "allan"}

这是指一个类,类里面有个变量名name。这个类的实例中的变量name值是Allan。这里我们要知道通讯的双发都要知道类的数据类型,比如变量那么的数据类型,都要是字符串。

json的语法主要是以{}内部的部分作为类的内容,内容都是以键值对存在,以:分开,前部分是类的变量名后部分是
变量值(这里我们知道变量名,通过反射可以设置类变量的内容。获取变量名也可以通过反射机制来实现,其实这里
我们完全自己写一套解析json的库)。

数组是通过[]来实现的如下:

//名字是个数组
{"name":["Michael","Jerry"]}

注意,类当中可以嵌套类,但是请注意。因为这不是xml语法,过分的嵌套不利于解析。阅读也会变得很困难。还是尽量减少嵌套。

大概意思是如下:

graph LR
A[JAVA 类] -- Gson--> B[Json格式的字符串]
B --Gson-->A

也许大家会有点蒙,为毛变成java类了,刚才解释json只是因为为了js类的一种记录语法,同样适用于java。作为一个Android程序员,我们只关注如何把从后台请求道的json字符串转换成我们需要的类,这是我们关注的。
下面我们关注我们真的逻辑。Gson到底如何做?
从github的userguide中我们可以看到最简单的一段代码

Gson gson = new Gson();
gson.toJson(1);            // ==> 1
gson.toJson("abcd");       // ==> "abcd"
gson.toJson(new Long(10)); // ==> 10
int[] values = { 1 };
gson.toJson(values);       // ==> [1]

// Deserialization
int one = gson.fromJson("1", int.class);
Integer one = gson.fromJson("1", Integer.class);
Long one = gson.fromJson("1", Long.class);
Boolean false = gson.fromJson("false", Boolean.class);
String str = gson.fromJson("\"abc\"", String.class);
String[] anotherStr = gson.fromJson("[\"abc\"]", String[].class);

那我们看下```toJson````函数:

  public void toJson(Object src, Type typeOfSrc, JsonWriter writer) throws JsonIOException {
    TypeAdapter<?> adapter = getAdapter(TypeToken.get(typeOfSrc));
   ......
      ((TypeAdapter<Object>) adapter).write(writer, src);
   
   ......
  }

这是核心代码,不过这代码读着真是坑,typeOfSrc这是toJson函数传入参数的类型的type(通过对参数进行getclass得到,比如第一个demo,得到的type是:((interge)1).getclass())
TypeToken.get(typeOfSrc)这个功能就比较强大了。TypeToken是一种类型,可有表示泛型类型。其实他就是封装了一下一个类,这个东西暂时不再详细介绍,总之就是每个类,都会有一个TypeToken,其中有个变量存储rawType。对于基本类型和类类型,都是直接返回自己的类型。getAdapter核心代码如下

public <T> TypeAdapter<T> getAdapter(TypeToken<T> type) {
......

    for (TypeAdapterFactory factory : factories) {
      TypeAdapter<T> candidate = factory.create(this, type);
      if (candidate != null) {
        call.setDelegate(candidate);
        typeTokenCache.put(type, candidate);
        return candidate;
    ......
}

我们知道在Gson构造函数的时候,初始化了factories。那我们回去看下这个factories

    List<TypeAdapterFactory> factories = new ArrayList<TypeAdapterFactory>();

  // built-in type adapters that cannot be overridden
  factories.add(TypeAdapters.JSON_ELEMENT_FACTORY);
  factories.add(ObjectTypeAdapter.FACTORY);

  // the excluder must precede all adapters that handle user-defined types
  factories.add(excluder);

  // user's type adapters
  factories.addAll(typeAdapterFactories);

  // type adapters for basic platform types
  factories.add(TypeAdapters.STRING_FACTORY);
  factories.add(TypeAdapters.INTEGER_FACTORY);
  factories.add(TypeAdapters.BOOLEAN_FACTORY);
  factories.add(TypeAdapters.BYTE_FACTORY);
  factories.add(TypeAdapters.SHORT_FACTORY);
  TypeAdapter<Number> longAdapter = longAdapter(longSerializationPolicy);
  factories.add(TypeAdapters.newFactory(long.class, Long.class, longAdapter));
  factories.add(TypeAdapters.newFactory(double.class, Double.class,
          doubleAdapter(serializeSpecialFloatingPointValues)));
  factories.add(TypeAdapters.newFactory(float.class, Float.class,
          floatAdapter(serializeSpecialFloatingPointValues)));
  factories.add(TypeAdapters.NUMBER_FACTORY);
  factories.add(TypeAdapters.ATOMIC_INTEGER_FACTORY);
  factories.add(TypeAdapters.ATOMIC_BOOLEAN_FACTORY);
  factories.add(TypeAdapters.newFactory(AtomicLong.class, atomicLongAdapter(longAdapter)));
  factories.add(TypeAdapters.newFactory(AtomicLongArray.class, atomicLongArrayAdapter(longAdapter)));
  factories.add(TypeAdapters.ATOMIC_INTEGER_ARRAY_FACTORY);
  factories.add(TypeAdapters.CHARACTER_FACTORY);
  factories.add(TypeAdapters.STRING_BUILDER_FACTORY);
  factories.add(TypeAdapters.STRING_BUFFER_FACTORY);
  factories.add(TypeAdapters.newFactory(BigDecimal.class, TypeAdapters.BIG_DECIMAL));
  factories.add(TypeAdapters.newFactory(BigInteger.class, TypeAdapters.BIG_INTEGER));
  factories.add(TypeAdapters.URL_FACTORY);
  factories.add(TypeAdapters.URI_FACTORY);
  factories.add(TypeAdapters.UUID_FACTORY);
  factories.add(TypeAdapters.CURRENCY_FACTORY);
  factories.add(TypeAdapters.LOCALE_FACTORY);
  factories.add(TypeAdapters.INET_ADDRESS_FACTORY);
  factories.add(TypeAdapters.BIT_SET_FACTORY);
  factories.add(DateTypeAdapter.FACTORY);
  factories.add(TypeAdapters.CALENDAR_FACTORY);
  factories.add(TimeTypeAdapter.FACTORY);
  factories.add(SqlDateTypeAdapter.FACTORY);
  factories.add(TypeAdapters.TIMESTAMP_FACTORY);
  factories.add(ArrayTypeAdapter.FACTORY);
  factories.add(TypeAdapters.CLASS_FACTORY);

  // type adapters for composite and user-defined types
  factories.add(new CollectionTypeAdapterFactory(constructorConstructor));
  factories.add(new MapTypeAdapterFactory(constructorConstructor, complexMapKeySerialization));
  this.jsonAdapterFactory = new JsonAdapterAnnotationTypeAdapterFactory(constructorConstructor);
  factories.add(jsonAdapterFactory);
  factories.add(TypeAdapters.ENUM_FACTORY);
  factories.add(new ReflectiveTypeAdapterFactory(
      constructorConstructor, fieldNamingStrategy, excluder, jsonAdapterFactory));

  this.factories = Collections.unmodifiableList(factories);

其实就是加了一大堆自带的factory,前边的主要是用来处理基本数据类型,是为了提高效率。我们先看最开始的factories.add(TypeAdapters.JSON_ELEMENT_FACTORY);这个东西是最终判断的类是JsonElement.class的子类,就返回特定的factory,用来转换类。第一个JsonElement貌似用的不多,我们不关注,第二个就更简单,是一个object。这个用的比较少。下面的几个主要是基本的数据类型。和一些常用的java提供的类型,比如sring、stringbuffer和集合。我们挑选一个最常用的String来看下

  public static final TypeAdapterFactory STRING_FACTORY = newFactory(String.class, STRING);
  
public static <TT> TypeAdapterFactory newFactory(
      final Class<TT> type, final TypeAdapter<TT> typeAdapter) {
    return new TypeAdapterFactory() {
      @SuppressWarnings("unchecked") // we use a runtime check to make sure the 'T's equal
      @Override public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
        return typeToken.getRawType() == type ? (TypeAdapter<T>) typeAdapter : null;
      }
      @Override public String toString() {
        return "Factory[type=" + type.getName() + ",adapter=" + typeAdapter + "]";
      }
    };
  }
public static final TypeAdapter<String> STRING = new TypeAdapter<String>() {
    @Override
    public String read(JsonReader in) throws IOException {
      JsonToken peek = in.peek();
      if (peek == JsonToken.NULL) {
        in.nextNull();
        return null;
      }
      /* coerce booleans to strings for backwards compatibility */
      if (peek == JsonToken.BOOLEAN) {
        return Boolean.toString(in.nextBoolean());
      }
      return in.nextString();
    }
    @Override
    public void write(JsonWriter out, String value) throws IOException {
      out.value(value);
    }
  };

String的factory是为了响应当需要string的时候。可以生成一个名字叫STRING 的内部类。我们看如何判断响应的,主要都是在STRING_FACTORY的create方法中,

public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
        return typeToken.getRawType() == type ? (TypeAdapter<T>) typeAdapter : null;
      }

getRawType()。是获取传入的类的类型,type是String.class.因为String是一个final类,所以也不存在继承的问题。直接返回名字叫STRING的适配器。
最后一个添加的factory是用来处理基本的类型,比如我们添加的bean类。我们看下:

public final class ReflectiveTypeAdapterFactory implements TypeAdapterFactory {
......
public <T> TypeAdapter<T> create(Gson gson, final TypeToken<T> type) {
    Class<? super T> raw = type.getRawType();

    if (!Object.class.isAssignableFrom(raw)) {
      return null; // it's a primitive!
    }
    ObjectConstructor<T> constructor = constructorConstructor.get(type);
    return new Adapter<T>(constructor, getBoundFields(gson, type, raw));
  }
  ......
  }

我们先看下String的处理方法,一会回过头看这个普通类的处理方法.
在toJson中我们可以看到得到adapter后,调用了

((TypeAdapter<Object>) adapter).write(writer, src);

String的write函数

    public void write(JsonWriter out, String value) throws IOException {
    out.value(value);

这就有点无语了,不过本来就是这样嘛,就是直接把字符串给写进去嘛!不信去写个demo试下。
然后我们开始读我们的ReflectiveTypeAdapterFactory,这是处理普通类的方法,主要是通过反射来实现的。
具体返回了哪个个adapter,我们看代码:

    @Override
   public <T> TypeAdapter<T> create(Gson gson, final TypeToken<T> type) {
       Class<? super T> raw = type.getRawType();

       if (!Object.class.isAssignableFrom(raw)) {
           return null; // it's a primitive!
       }

       System.out.println("this is the reflective factory");
       ObjectConstructor<T> constructor = constructorConstructor.get(type);
       return new Adapter<T>(constructor, getBoundFields(gson, type, raw));
   }

我们要关注getBoundFields(gson, type, raw)这个的东西,这才是通过反射来实现的获得必要的参数表,可以转换。我们看下代码:

private Map<String, BoundField> getBoundFields(Gson context, TypeToken<?> type, Class<?> raw) {
        Map<String, BoundField> result = new LinkedHashMap<String, BoundField>();
        //借口返回空
        if (raw.isInterface()) {
            return result;
        }

        Type declaredType = type.getType();
        while (raw != Object.class) {
            Field[] fields = raw.getDeclaredFields();
            for (Field field : fields) {
                ......
                List<String> fieldNames = getFieldNames(field);
                BoundField previous = null;
                for (int i = 0, size = fieldNames.size(); i < size; ++i) {
                    String name = fieldNames.get(i);
                    if (i != 0) serialize = false; // only serialize the default name
                    BoundField boundField = createBoundField(context, field, name,
                            TypeToken.get(fieldType), serialize, deserialize);
                    BoundField replaced = result.put(name, boundField);
                    if (previous == null) previous = replaced;
                }
                if (previous != null) {
                    throw new IllegalArgumentException(declaredType
                            + " declares multiple JSON fields named " + previous.name);
                }
            }
            type = TypeToken.get($Gson$Types.resolve(type.getType(), raw, raw.getGenericSuperclass()));
            raw = type.getRawType();
        }
        return result;
    }

这个代码貌似比较复杂,但是我们如果仔细分析,还是很容易理解的,首先是接口情况,直接返回一个空map,关键是后半部分,两层循环也是很容易理解的,第一层通过循环是为了解决继承关系,指导到object,第二层是为了每层类的变量表加入result 中。我们就看对单一变量的处理,getFieldNames(field),功能简单,可是实现比较复杂,其实就是通过反射,得到变量的名字,我们看代码:

/**
     * first element holds the default name
     */
    private List<String> getFieldNames(Field f) {
    	//这个东东是为了实现变量名的改变,因为在代码中和传输过程中变量名可能不一样。
        SerializedName annotation = f.getAnnotation(SerializedName.class);
        //如果没有注释的变更变量名字,可以直接返回了,
        if (annotation == null) {
            String name = fieldNamingPolicy.translateName(f);
            return Collections.singletonList(name);
        }

	//别名必须有,
        String serializedName = annotation.value();
       // 可选的别名,没什么卵用
        String[] alternates = annotation.alternate();
        if (alternates.length == 0) {
            return Collections.singletonList(serializedName);
        }

        List<String> fieldNames = new ArrayList<String>(alternates.length + 1);
        fieldNames.add(serializedName);
        //记住这里对于同一个变量,可以添加多次,但是最后只会显示出一个并且只会显示value值,而解析时候,就必须这个可选别名了。
        for (String alternate : alternates) {
            fieldNames.add(alternate);
        }
        return fieldNames;
    }

总之这里只是返回至少一个名字的列表,最关键的是在getBoundFields的添加,我们重新看下这部分代码:

BoundField boundField = createBoundField(context, field, name,
                            TypeToken.get(fieldType), serialize, deserialize);
                    BoundField replaced = result.put(name, boundField);

构建一个BoundField添加一个列表,我们开始看真的adapter干了什么:

 @Override
       public void write(JsonWriter out, T value) throws IOException {
           ......

           out.beginObject();
           try {
               for (BoundField boundField : boundFields.values()) {
                   if (boundField.writeField(value)) {
                       out.name(boundField.name);
                       boundField.write(out, value);
                   }
               }
           } catch (IllegalAccessException e) {
               throw new AssertionError(e);
           }
           out.endObject();
       }
   }

boundField.write(out, value);,这个东东代码比较复杂,因为需要一个递归调用,如果变量类型不是基础类型,就必须可以把它转换成基础类型,这部分代码如下,我自己也不想在去完全看懂,

 private ReflectiveTypeAdapterFactory.BoundField createBoundField(
            final Gson context, final Field field, final String name,
            final TypeToken<?> fieldType, boolean serialize, boolean deserialize) {
        //核心在这里,在此找到一个adapter
        if (mapped == null) mapped = context.getAdapter(fieldType);

        final TypeAdapter<?> typeAdapter = mapped;
        return new ReflectiveTypeAdapterFactory.BoundField(name, serialize, deserialize) {
            @SuppressWarnings({"unchecked", "rawtypes"})
            // the type adapter and field type always agree
            @Override
            void write(JsonWriter writer, Object value)
                    throws IOException, IllegalAccessException {
                Object fieldValue = field.get(value);
                TypeAdapter t = jsonAdapterPresent ? typeAdapter
                        : new TypeAdapterRuntimeTypeWrapper(context, typeAdapter, fieldType.getType());
                        //再次调用刚才的adapter,然后写入内容,这是给递归调用,所有流程over
                t.write(writer, fieldValue);
            }

            @Override
            void read(JsonReader reader, Object value)
                    throws IOException, IllegalAccessException {
                Object fieldValue = typeAdapter.read(reader);
                if (fieldValue != null || !isPrimitive) {
                    field.set(value, fieldValue);
                }
            }

           ......
    }

其实这些内容放在开始就会觉得很简单,只用反射机制,就可以完成所有内容,关于解析json数据,还没看,这里就不一一写了,大家可以自己阅读代码。
总结下这里其实很简单:
拿到一个对象。先判断他是不是基础类型,是的话,就直接转换。不是的话,就需要通过反射得到变量。对每个变量在进行上述操作,
其实我们完全可以自己写个简单的类。有机会自己实践一下,只可以识别String类和对象。

后记

终于搞定这篇东东,里面比较多的用到反射泛型和注释编程,这些东东真是无法理解,这里跟踪主要流程完成了大概的一部分内容,关于逆向转换,里面的断句等等,应该还是比较复杂,不过这应该可以解决。我们不再在这个上面纠结。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值