Gson源码解析
来源:互联网 发布:网络教育好找工作吗 编辑:程序博客网 时间:2024/06/06 00:05
我个人觉得 Gson是一个非常优秀的json解析开源项目,效率高, 代码结构也非常的清晰 。给使用者提供了非常好的用户体验。封装也非常的优雅 。因此, 我对Gson的研究充满了兴趣,这里顺带提一下我前两天发现的一个非常不错的Rest封装框架: Retrofit, 我不知道知道的人有多少, 我之前一直使用的是自己写的Rest封装,代码的 复用 性也不强, 而Retrofit却把这样东西做了极致。我 将在后面的文章中研究它。 你可能很少不了 @子墨 这种想到哪写到哪的做法。不过如果 你看 的顺眼就不妨跟 着 这不成文的节奏走吧,因为我不打算改变我的写作方式。
回到 正题, Gson主要分成两部分 ,一个就是 数据拆解,一个是数据封装。这两个概念我都是基于JSON 层的概念而言。这样JSON对象的拆解 的结果就是JAVA对象,而所谓的封装就是将一个OO的对象封装成为一个json对象。当然json对象可以理解为就是一个字符串。那么实际上Gson做的事情就是完成St ring到JAVA 对象的映射。我们建立起这个概念以后我们就能明白我们的 研究主要分成两个大部分。前几个系列我们会先说String到JAVA对象之间的映射。
我们 导入Gson的源码 发现代码比 预想的少的多, 分包也很明确。你是不是瞬间对Google公司崇敬起来。我们明白, 如果要对 系统之上构建一个封装的 话,用的就是门面模式 , 关于门面模式的说法,大家可以参考 我的一篇文章:
子墨对酒《三国杀》里论模式(二)门面模式
构造门面的 包名一般都是所有系统的顶层包。我们看到 com.google.gson 就很好的封装了这些门面。也就是说我们要跟系统打交道, 实际上就是要跟这些门面打 交道。
String 到 对象的主要门面是Gson .java。 里面提供了各种各样的方法方便你调用。
public <T> 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<T> typeToken = (TypeToken<T>) TypeToken.get(typeOfT); TypeAdapter<T> 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<T> typeAdapter这个对象来完成的,我们可以从名字看出它本质上一个适配器。关于适配器模式大家可以参考 我的 一篇文章:
子墨对酒《三国杀》里论模式(三)适配器模式
为什么需要适配 器呢 ?我们粘出一个适配器的代码相信大家就能了解了:public final class DateTypeAdapter extends TypeAdapter<Date> { public static final TypeAdapterFactory FACTORY = new TypeAdapterFactory() { @SuppressWarnings("unchecked") // we use a runtime check to make sure the 'T's equal public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) { return typeToken.getRawType() == Date.class ? (TypeAdapter<T>) 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并不知道什么时候要用它来适配,它的适配要完全依赖于这些适配器。当你传入的是适配器 判断条件所需的字节码条件的时候, 就将采用该种适配器来进行适配 。 但是令人非常遗憾的是: 在gson这个门面的设计的时候,并没有提供接口用来factory的扩展,这样 你就得完全按照Gson的那一套规则 。 而且对于 一个对象的生成采用成文的规定,完全没有给外界修改的权利。但是这 并不会影响G son作为一个出色的项目,优雅的代码结构而存在。
代码中让我们非常崩溃的就是大量的匿名类,不过Gson似乎也意识到了这个问题:
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 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 + "]"; } }; }我们发现它使用通用的模板来生成类,无可厚非。而且也复写了toString为了方便调试。我 写了一段代码来做测试:
/** * @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.bindGson:>>>com.google.gson.internal.bind.ReflectiveTypeAdapterFactory@6030e280Gson:create type = com.test.TestGson$InfoGson:>>>com.google.gson.internal.bind.ReflectiveTypeAdapterFactory@6030e280Gson:create type = com.test.TestGson$User这里面我 加了一些log ,我们可以通过这些log能很明白的理解Gson的总体解析结构,就是顺序解析, 如果是对象的 话是通过
ReflectiveTypeAdapterFactory
这个类生成的Adapter对象来生成。我们也会发现,作为最终要解析成的对象User, 实际上 是最后解析的, 因此我们推测,解析完 内部对象以后采用组合的方式来注入。至于组合模式,将会在我以后关于 <三国杀>设计模式的文章 中 补充到。由于时间的 关系 本系列文章将会分成多个小节来写, 下一篇我希望还是像Proguard源码分析一样 先从Json的数据读 取开始, 主要的类是:
JsonReader .java
待续。。。
- GSON源码解析
- Gson源码解析
- Gson 源码解析
- Gson 源码解析-2015/10/13
- 源码简读之Gson解析
- Gson源码
- Gson解析
- GSON解析
- Gson解析
- Gson解析
- Gson解析
- Gson解析
- GSON解析
- Gson解析
- Gson解析
- Gson解析
- Gson解析
- Gson 解析
- java程序调试中常见错误及原因汇总
- erlang 监控树 参数策略
- 机器学习笔记--闵氏距离学习
- Enable Bitcode 一种中间代码
- Control Group v2
- Gson源码解析
- systemctl 命令完全指南
- 标准Jquery Ajax
- 并发访问sqlite数据库出现databse is locked的错误的一个解决办法
- JQ动态加载下拉框数据
- Android视图状态及重绘流程分析,带你一步步深入了解View(三)
- Java运行机制
- JSON 之FastJson解析
- 论文word编辑教训