Gson中@JsonAdater注解的几种方式总结

2022-08-30 11:11:16

目录Gson@JsonAdater注解的几种方式总结问题描述方式一方式二-write原样方式三-简单写法Gson注解@SerializedNameExposeGson@JsonAdater注解的几...

目录
Gson @jsonAdater注解的几种方式
总结
问题描述
方式一
方式二-write原样
方式三-简单写法
Gson注解
@SerializedName
Expose

Gson @JsonAdater注解的几种方式

总结

可以通过自定义TypeAdapter和TypeAdapterFactory的方式,自定义gson的序列化和反序列规则,TypeAdapterFactory可以拿到上下文gson、TokenType类型;

也可以通过继承JsonReader重新写一次代码,在beginArray和endArray想办法跳过array的string形式的左右 双引号", gson.fromJson(myJsonReader, Type)也可以实现 解析时自动将String变为List,但采用注解@JsonAdapter的方式更为正规一些;

问题描述

json字符串:

{
  "cityIds": "[1,2,1001,13131]",
  "types": "[{\"name\": \"biz\",\"details\": [1]}]"
}

Java对象定义:

@Data
  public static class RequestParams {
   // json字符串里对应的是String
    private List<TypeItem> types;
    private List<Integer> cityIds;
  }
  @Data
  public static class TypeItem {
    private String name;
    private List<Integer> details;
  }

可以看到json里面cityIds和types都是String,而pojo里则是List,使用gson的fromJson将json转为pojo会发生报错

方式一

 @JsonAdapter(StringCollectionTypeAdapterFacjavascripttory.class)
  private List<TagItem> tags;
  @JsonAdapter(StringCollectionTypeAdapterFactory.class)
  private List<Integer> cityIds;
public static class StringCollectionTypeAdapterFactory implements TypeAdapterFactory {
    @Override
    public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
      // 为了write的时候能使用到elementTypeAdapter
      Type type = typeToken.getType();
      Class<? super T> rawType = typeToken.getRawType();
      if (!Collection.class.isAssignableFrom(rawType)) {
        return null;
      }
      Type elementType = $Gson$Types.getCollectionElementType(type, rawType);
      TypeAdapter<?> elementTypeAdapter = gson.getAdapter(TypeToken.get(elementType));
     
      TypeAdapter<T> result = new Adapter(gson, elementTypeAdapter, typeToken);
      return result;
    }
    private static final class Adapter<E> extends TypeAdapter<Collection<E>> {
      private final TypeAdapter<E> elementTypeAdapter;
      private final Gson gson;
      private final TypeToken listType;
      public Adapter(Gson context, TypeAdapter<E> elementTypeAdapter, TypeToken listType) {
        this.elementTypeAdapter = elementTypeAdapter;
        this.gson = context;
        this.listType = listType;
      }
      @Override public Collection<E> read(JsonReader in) throws IOException {
        if (in.peek() == JsonToken.NULL) {
          in.nextNull();
          return null;
        }
        List<E> list = gson.fromJson(in.nextString(), listType.getType());
        return list;
      }

      // write后可以将array的string格式,重新变成array
      @Override public void write(JsonWriter out, Collection<E> collection) throws IOException {
        if (collection == null) {
          out.nullValue();
          return;
        }
        out.beginArray();
        for (E element : collection) {
          elementTypeAdapter.write(out, element);
        }
        out.endArray();
      }
    }
  }

方式二-write原样

public static class StringCollectionTypeAdapterFactory1 implements TypeAdapterFactory {
    @Override
    public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
      return new Adapter(gson, typeToken);
    }
    private static final class Adapter<E> extends TypeAdapter<Collection<E>> {
      private final Gson gson;
      private final TypeToken listType;
      public Adapter(Gson context, TypeToken listType) {
        this.gson = context;
        this.listType = listType;
      }
      @Override public Collection<E> read(JsonReader in) throws IOException {
        if (in.peek() == JsonToken.NULL) {
          in.nextNull();
          return null;
        }
        List<E> list = gson.fromJson(in.nextString(), listType.getType());
        return list;
      }
      @Override public void write(JsonWriter out, Collection<E> collection) throws IOException {
        if (collection == null) {
          out.nullValue();
          return;
        }
        out.value(gson.toJson(collection));
      }
    }
  }

方式三-简单写法

private static class CollectionStringTypeAdapterFactory implements TypeAdapterFactory {
    @Override
    public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
      return new TypeAdapter<T>() {
        @Override
        public void write(JsonWriter out, T value) throws IOException {
          if (value == null) {
            out.nullValue();
            return;
          }
          gson.getAdapter(type).write(out, value);
        }
        @Override
        public T read(JsonReader in) throws IOException {
          if (in.peek() == JsonToken.NULL) {
            return null;
          }
          if (in.peek() == JsonToken.BEGIN_ARRAY) {
            return gson.getAdapter(type).read(in);
          }
          T collection = gson.fromJson(in.nextString(), type.getType());
          return collection;
        }
      };
    }
  }

测试用例如下所示:

@Test
  public void testGson1() {
    Gson gson = new Gson();
    RequestParams requestParam;
    String json;
    // 1.自动将string转为属性的List
    json = "{\"id\": \"000000\",\"types\": \"[{\\\"name\\\":\\\"name1\\\",\\\"list\\\":[1,2]},{\\\"name\\\":\\\"name2\\\",\\\"list\\\":[3,4]}]\",\"keywordIds\": \"[12,13]\"}";
    System.out.println(json);
    requestParam = gson.fromJson(json, new TypeToken<RequestParams>() {}.getType());
    Assert.assertTrue(requestParam.getTypes().get(0).getClass().getName().indexOf("TypeItem") >= 0);
    System.out.println(gson.toJson(requestParam));
    // 2.jsonArray也可以转为List
    json = "{\"id\": \"000000\",\"keywordIds\": [12,13],\"types\": [{\"name\":\"name1\",\"list\":[1,2]},{\"name\":\"name2\",\"list\":[3,4]}]}";
    requestParam = gson.fromJson(json, new TypeToken<RequestParams>() {}.getType());
    Assert.assertTrue(requestParam.getTypes().get(0).getClass().getName().indexOf("TypeItem") >= 0);
    System.out.println(gson.toJson(requestParam));
    // 3.换行的方式呢
    json = "{\n" +
        "\t\"id\": \"000000\",\n" +
        "\t\"keywordIds\": [12,13],\n" +
        "\t\"types\": [{\"name\":\"name1\",\"list\":[1,2]},{\"name\":\"name2\",\"list\":[3,4]}]\n" +
        "}";
    requestParam = gson.fromJson(json, new TypeToken<RequestParams>() {}.getType());
    Assert.assertTrue(requestParam.getTypes().get(0).getClass().getName().indexOf("TypeItem") >= 0);
    System.out.println(gson.toJson(requestParam));
    // 4.能否将List里面的Integer变成String呢
    json = "{\n" +
        "\t\"id\": \"000000\",\n" +
        "\t\"keywordIds\": [12,13],\n" +
        "\t\"types\": [{\"name\":\"name1\",\"list1\":[1,2]},{\"name\":\"name2\",\"list1\":[3,4]}]\n" +
        "}";
    requestParam = gson.fromJson(json, new TypeToken<RequestParams>() {}.getType());
    Assert.assertTrue(requestParam.getTypes().get(0).getClass().getName().indexOf("TypeItem") >= 0);
    System.out.println(gson.toJson(requestParam));
    // 5.能否将List里面的Integer变成String
    json = "{\n" +
        "\t\"id\": \"000000\",\n" +
        "\t\"keywordIds1\": [12,13],\n" +
        "\t\"types\": [{\"name\":\"name1\",\"www.cppcns.comlist1\":[1,2]},{\"name\":\"name2\",\"list1\":[3,4]}]\n" +
        "}";
    requestParam = gson.fromJson(json, new TypeToken<RequestParams>() {}.getType());
    Assert.assertTrue(requestParam.getTypes().get(0).getClass().getName().indexOf("TypeItem") >= 0);
    System.out.println(gson.toJson(requestParam));
    // 6.自动将string转为属性的List, 并且list里面的Integer变为String
    json = "{\"id\": \"000000\",\"types\": \"[{\\\"name\\\":\\\"name1\\\",\\\"list1\\\":[1,2]},{\\\"name\\\":\\\"name2\\\",\\\"list1\\\":[3,4]}]\",\"keywordIds1\": \"[12,13]\"}";
    System.out.println(json);
    requestParam = gson.fromJson(json, new TypeToken<RequestParams>() {}.getType());
    Assert.assertTrue(requestParam.getTypes().get(0).getClass().getName().indexOf("TypeItem") >= 0);
    System.out.pandroidrintln(gson.toJson(requestParam));
  }
  @Data
  public static class RequestParams {
    private String id;
    @JsonAdapter(CollectionStringTypeAdapterFactory.class)
    private List<TypeItem> types;
    @JsonAdapter(CollectionStringTypeAdapterFactory.class)
    private List<Integer> keywordIds;
    @JsonAdapter(CollectionStringTypeAdapterFactory.class)
    private List<String> keywordIds1;
  }
  @Data
  public static class TypeItem {
    private String name;
    private List<Integer> list;
    private List<String> list1;
  }

Gson注解

@SerializedName

主要应用在Gson解析json字符串时。Gson能直接将json字符串解析成java对象或者集合,也能将java对象转换为json字符串表示。例如有json数据如下:

{
  "id":"1"
  "n":"zhangsan"
  "p":"123456"
  "s":"0"
}

它能被解析到下面这个对象

public class User{
  private String id;
  private String n;
  private String p;
  private string s;
}

默认在字段名相同的字段间解析,所以User类必须要这样写才能直接使用Gson解析出来,但是java对象里的属性名和json里的字段名有时会不一样。Gson提供注解的方法来解决这个问题。

public class User{

  private String id;

  @SerializedName("n")
  private String userName;

  @SerializedName("p")
  private String password;

  @SerializedName("s")
  private String sex;
}

Expose

通常与@SerializedName连用,当我们不想把某个属性包含到json中时可以用。

public class UserSimple { 
  @Expose()
  String name; // equals serialize & deserialize

  @Expose(serialize = false, deserialize = false)
  String email;

  @Expose(serialize = false)
  int age;

  @Expose(deserialize = false)
  boolean isDeveloper; // equals only serialize
}

序列化的结果将只有name和isDeveloper出现在json中,因为serialize都是false。反序列化时,java对象将只会拥有json中的name和age,因为diserialze是true。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。