Gson学习记录

  Gson是Google开发来用来序列化和反序列化json格式数据的java库,他最大的特点就是对复杂类型的支持度高,可以完美解决java泛型问题,这得益于他对泛型类型数据的特殊处理,他的缺点就是速度慢。

  我们首先看下例子:

List<MerchantMessage> merchants = new ArrayList<MerchantMessage>();
        MerchantMessage m1 = new MerchantMessage();
        List<Photo> p1 = new ArrayList<Photo>();
        p1.add(new Photo("zcm", "http://zcm.jpg"));
        m1.setPhotos(p1);
        m1.setAdcode("123");
        m1.setAddress(123123);
        m1.setBusinessArea("hello");
        merchants.add(m1);
        ResponseMerchantResult result = new ResponseMerchantResult(0, merchants);
        String json = Gson.toJson(result);
     Gson.formJson(json,
ResponseMerchantResult.class);

  我们构建了一个ResponseMerchantResult类型的数据,然后执行Gson.toJson方法,然后就可以得到相应的json字符串,我们来看下解析过程

  最终Gson会执行到这个方法:

 @SuppressWarnings("unchecked")
  public void toJson(Object src, Type typeOfSrc, JsonWriter writer) throws JsonIOException {
    TypeAdapter<?> adapter = getAdapter(TypeToken.get(typeOfSrc));
    boolean oldLenient = writer.isLenient();
    writer.setLenient(true);
    boolean oldHtmlSafe = writer.isHtmlSafe();
    writer.setHtmlSafe(htmlSafe);
    boolean oldSerializeNulls = writer.getSerializeNulls();
    writer.setSerializeNulls(serializeNulls);
    try {
      ((TypeAdapter<Object>) adapter).write(writer, src);
    } catch (IOException e) {
      throw new JsonIOException(e);
    } finally {
      writer.setLenient(oldLenient);
      writer.setHtmlSafe(oldHtmlSafe);
      writer.setSerializeNulls(oldSerializeNulls);
    }
  }

我们来分析下:  

getAdapter(TypeToken.get(typeOfSrc));

这个代码是获取到解析解析的适配器,根据typeOfSrc匹配现有的适配器,以后所有的操作就是这个适配器来完成。
  @SuppressWarnings("unchecked")
  public <T> TypeAdapter<T> getAdapter(TypeToken<T> type) {
    TypeAdapter<?> cached = typeTokenCache.get(type == null ? NULL_KEY_SURROGATE : type);
    if (cached != null) {
      return (TypeAdapter<T>) cached;
    }

    Map<TypeToken<?>, FutureTypeAdapter<?>> threadCalls = calls.get();
    boolean requiresThreadLocalCleanup = false;
    if (threadCalls == null) {
      threadCalls = new HashMap<TypeToken<?>, FutureTypeAdapter<?>>();
      calls.set(threadCalls);
      requiresThreadLocalCleanup = true;
    }

    // the key and value type parameters always agree
    FutureTypeAdapter<T> ongoingCall = (FutureTypeAdapter<T>) threadCalls.get(type);
    if (ongoingCall != null) {
      return ongoingCall;
    }

    try {
      FutureTypeAdapter<T> call = new FutureTypeAdapter<T>();
      threadCalls.put(type, call);

      for (TypeAdapterFactory factory : factories) {
        TypeAdapter<T> candidate = factory.create(this, type);
        if (candidate != null) {
          call.setDelegate(candidate);
          typeTokenCache.put(type, candidate);
          return candidate;
        }
      }
      throw new IllegalArgumentException("GSON cannot handle " + type);
    } finally {
      threadCalls.remove(type);

      if (requiresThreadLocalCleanup) {
        calls.remove();
      }
    }
  }

我们看到这个方法会遍历所有的适配器工厂,然后得到一个合适的,我们对Gson扩展时最大的扩展点就是这个地方,你可以替换他本身的适配器工厂,也可以添加你需要的工厂。

我们来看下最常用的一个适配器工厂ReflectiveTypeAdapterFactory  --- 反射类型适配器工厂类  

  

@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!
    }

    ObjectConstructor<T> constructor = constructorConstructor.get(type);
    return new Adapter<T>(constructor, getBoundFields(gson, type, raw));
  }
最关键的就是这个create方法,这个方法最终会创建一个需要的适配器,这个适配器工厂会放在所有工厂的最后,当我们要解析的类不是基本类或常用的java类时,就会使用这个工厂来解析
我们看到getBoundFields()方法
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) {
        boolean serialize = excludeField(field, true);
        boolean deserialize = excludeField(field, false);
        if (!serialize && !deserialize) {
          continue;
        }
        field.setAccessible(true);
        Type fieldType = $Gson$Types.resolve(type.getType(), raw, field.getGenericType());
        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;
  }

看到这里我们就会发现会获取所有的字段,然后为每个字段绑定他对应的适配器,这样被解析类的每个属性都有了相应的解析适配器,接下来就可以进行解析了

public void toJson(Object src, Type typeOfSrc, JsonWriter writer) throws JsonIOException {
    TypeAdapter<?> adapter = getAdapter(TypeToken.get(typeOfSrc));
    boolean oldLenient = writer.isLenient();
    writer.setLenient(true);
    boolean oldHtmlSafe = writer.isHtmlSafe();
    writer.setHtmlSafe(htmlSafe);
    boolean oldSerializeNulls = writer.getSerializeNulls();
    writer.setSerializeNulls(serializeNulls);
    try {
      ((TypeAdapter<Object>) adapter).write(writer, src);
    } catch (IOException e) {
      throw new JsonIOException(e);
    } finally {
      writer.setLenient(oldLenient);
      writer.setHtmlSafe(oldHtmlSafe);
      writer.setSerializeNulls(oldSerializeNulls);
    }
  }

我们看到这里会调用适配器的write方法:

  public void write(JsonWriter out, T value) throws IOException {
      if (value == null) {
        out.nullValue();
        return;
      }

      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();
    }
  }

这里会循环所有的属性,然后调用对应的适配器的write方法,最终序列化就完成了。

我觉得Gson最好的地方就是他可以自动适配泛型类型,我们来看个类

public class TypeToken<T> {
  final Class<? super T> rawType;
  final Type type;
  final int hashCode;

@SuppressWarnings("unchecked")
TypeToken(Type type) {
this.type = $Gson$Types.canonicalize($Gson$Preconditions.checkNotNull(type));
this.rawType = (Class<? super T>) $Gson$Types.getRawType(this.type);
this.hashCode = this.type.hashCode();
}
}

这个类是Gson用来记录解析过程需要的type类型,当寻找适配器时就是根据这个类来寻找符合的适配器的,所以泛型的配置也是在这个类里配置。

我们来看下怎么配置这个类

  首先看几个基本类

public class GenericResult<T>{
    
    private long l1;
    
    private double d1;
    
    private int i1;
    
    private String s1;
    
    private List<T> datas;

    
}
public class Message<T> {
    
    private List<T> data;

    public List<T> getData() {
        return data;
    }

    public void setData(List<T> data) {
        this.data = data;
    }
    
    
    
}
GenericResult<Message> result2 = new GenericResult<Message>();
        Message<MerchantMessage> message = new Message();
        message.setData(merchants);
        result2.setD1(11d);
        result2.setI1(1);
        result2.setL1(11l);
        result2.setS1("11");
        result2.setDatas(Arrays.asList(message));
        String json2 = JsonTool.toJson(result2);

我们看到最后这段代码,这段代码主要是构建一个java类,其中主要类是GenericResult,然后他包含泛型类型Message,Message包含泛型类型MerchantMessage

那我们解析的时候怎么解析呢

我们需要一个辅助类

  下面或者类就可以记录我们所有的类型,我们看下怎么使用

public class TypeMessage implements ParameterizedType{
    
    private final Class main;
    
    private final Type[] args;
    
    public TypeMessage(Class main,Type[] args){
        this.main = main;
        this.args = args == null ? new Type[0] : args;
    }
    
    @Override
    public Type[] getActualTypeArguments() {
        return this.args;
    }

    @Override
    public Type getRawType() {
        return this.main;
    }

    @Override
    public Type getOwnerType() {
        return null;
    }
    
}
JsonTool.<GenericResult>toJson(json2,
                new TypeMessage(
                        GenericResult.class,
                        new Type[]{new TypeMessage(Message.class,new Type[]{MerchantMessage.class})}))

当Gson去解析的时候就会按照我们配置的类型去解析。这样我们的泛型就被我们放置进去了。

以上就是toJson的解析,formJson的解析和toJson类似这里就不再看了。










猜你喜欢

转载自www.cnblogs.com/zcmzex/p/9068532.html