因为工作的关系,使用到了Gson,先暂停了书写Proguard的文章,回到Gson的研究。当然也不会总是研究Gson,我会两个项目跳着来。完全按照自己的兴趣来。我个人觉得Gson是一个非常优秀的json解析开源项目,效率高,代码结构也非常的清晰。给使用者提供了非常好的用户体验。封装也非常的优雅。因此,我对Gson的研究充满了兴趣,这里顺带提一下我前两天发现的一个非常不错的Rest封装框架:Retrofit,我不知道知道的人有多少,我之前一直使用的是自己写的Rest封装,代码的复用性也不强,而Retrofit却把这样东西做了极致。我将在后面的文章中研究它。你可能很少不了@子墨这种想到哪写到哪的做法。不过如果你看的顺眼就不妨跟着这不成文的节奏走吧,因为我不打算改变我的写作方式。
回到正题,Gson主要分成两部分,一个就是数据拆解,一个是数据封装。这两个概念我都是基于JSON层的概念而言。这样JSON对象的拆解的结果就是JAVA对象,而所谓的封装就是将一个OO的对象封装成为一个json对象。当然json对象可以理解为就是一个字符串。那么实际上Gson做的事情就是完成String到JAVA对象的映射。我们建立起这个概念以后我们就能明白我们的研究主要分成两个大部分。前几个系列我们会先说String到JAVA对象之间的映射。
我们导入Gson的源码发现代码比预想的少的多,分包也很明确。你是不是瞬间对Google公司崇敬起来。我们明白,如果要对系统之上构建一个封装的话,用的就是门面模式,关于门面模式的说法,大家可以参考我的一篇文章:
构造门面的包名一般都是所有系统的顶层包。我们看到com.google.gson就很好的封装了这些门面。也就是说我们要跟系统打交道,实际上就是要跟这些门面打交道。
String 到对象的主要门面是Gson.java。里面提供了各种各样的方法方便你调用。
public T fromJson(JsonReader reader, Type typeOfT) throws JsonIOException, JsonSyntaxException {
boolean isEmpty = true;
boolean oldLenient = reader.isLenient();
reader.setLenient(true);
try {
reader.peek();
isEmpty = false;
TypeToken typeToken = (TypeToken) TypeToken.get(typeOfT);
TypeAdapter typeAdapter = getAdapter(typeToken);
T object = typeAdapter.read(reader);
System.out.println("object = "+object);
return object;
} catch (EOFException e) {
/*
* For compatibility with JSON 1.5 and earlier, we return null for empty
* documents instead of throwing.
*/
if (isEmpty) {
return null;
}
throw new JsonSyntaxException(e);
} catch (IllegalStateException e) {
throw new JsonSyntaxException(e);
} catch (IOException e) {
// TODO(inder): Figure out whether it is indeed right to rethrow this as JsonSyntaxException
throw new JsonSyntaxException(e);
} finally {
reader.setLenient(oldLenient);
}
}
我们能比较清晰的看到,
实际上对于数据的转换,是由:TypeAdapter
public final class DateTypeAdapter extends TypeAdapter {
public static final TypeAdapterFactory FACTORY = new TypeAdapterFactory() {
@SuppressWarnings("unchecked") // we use a runtime check to make sure the 'T's equal
public TypeAdapter create(Gson gson, TypeToken typeToken) {
return typeToken.getRawType() == Date.class ? (TypeAdapter) new DateTypeAdapter() : null;
}
};
private final DateFormat enUsFormat
= DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, Locale.US);
private final DateFormat localFormat
= DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT);
private final DateFormat iso8601Format = buildIso8601Format();
private static DateFormat buildIso8601Format() {
DateFormat iso8601Format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US);
iso8601Format.setTimeZone(TimeZone.getTimeZone("UTC"));
return iso8601Format;
}
@Override public Date read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
return deserializeToDate(in.nextString());
}
private synchronized Date deserializeToDate(String json) {
try {
return localFormat.parse(json);
} catch (ParseException ignored) {
}
try {
return enUsFormat.parse(json);
} catch (ParseException ignored) {
}
try {
return iso8601Format.parse(json);
} catch (ParseException e) {
throw new JsonSyntaxException(json, e);
}
}
@Override public synchronized void write(JsonWriter out, Date value) throws IOException {
if (value == null) {
out.nullValue();
return;
}
String dateFormatAsString = enUsFormat.format(value);
out.value(dateFormatAsString);
}
}
代码中让我们非常崩溃的就是大量的匿名类,不过Gson似乎也意识到了这个问题:
public static TypeAdapterFactory newFactory(
final Class type, final TypeAdapter typeAdapter) {
return new TypeAdapterFactory() {
@SuppressWarnings("unchecked") // we use a runtime check to make sure the 'T's equal
public TypeAdapter create(Gson gson, TypeToken typeToken) {
return typeToken.getRawType() == type ? (TypeAdapter) typeAdapter : null;
}
@Override public String toString() {
return "Factory[type=" + type.getName() + ",adapter=" + typeAdapter + "]";
}
};
}
/**
* @author 非子墨
* */
public class TestGson {
public static class User{
public String name;
public int age;
public Info info;
@Override
public String toString() {
// TODO Auto-generated method stub
return "["+name+":"+info.msg+"]";
}
}
public static class Info{
public Info() {}
String msg;
}
public static void main(String[] args) {
String gsonValue = "{name:'非子墨',age:23,info:{msg:'I am a student!'}}";
Gson gson = new Gson() ;
User user = gson.fromJson(gsonValue, User.class);
System.out.println("user = "+user);
}
}
Gson:>>>Factory[type=java.lang.String,adapter=com.google.gson.internal.bind.TypeAdapters$13@398020cc]
Gson:>>>Factory[type=java.lang.Integer+int,adapter=com.google.gson.internal.bind
Gson:>>>com.google.gson.internal.bind.ReflectiveTypeAdapterFactory@6030e280
Gson:create type = com.test.TestGson$Info
Gson:>>>com.google.gson.internal.bind.ReflectiveTypeAdapterFactory@6030e280
Gson:create type = com.test.TestGson$User
ReflectiveTypeAdapterFactory
这个类生成的Adapter对象来生成。我们也会发现,作为最终要解析成的对象User,
实际上是最后解析的,因此我们推测,解析完内部对象以后采用组合的方式来注入。至于组合模式,将会在我以后关于<三国杀>设计模式的文章中补充到。
由于时间的关系本系列文章将会分成多个小节来写,下一篇我希望还是像Proguard源码分析一样先从Json的数据读取开始,主要的类是:
JsonReader.java
待续。。。