##前言
网络请求框架一直没搞,这个东西一直是我的一个遗憾。最近用到这里我们好好的研究下,本篇博客主要研究一下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类和对象。
后记
终于搞定这篇东东,里面比较多的用到反射泛型和注释编程,这些东东真是无法理解,这里跟踪主要流程完成了大概的一部分内容,关于逆向转换,里面的断句等等,应该还是比较复杂,不过这应该可以解决。我们不再在这个上面纠结。