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 

待续。。。 

0 0
原创粉丝点击