Gson中@JsonAdater註解的幾種方式總結
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(StringCollectionTypeAdapterFactory.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\",\"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)); // 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.println(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。
以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。
推薦閱讀:
- Java中Json與List、Map、entity的互相轉化
- Android Gson基本用法學習
- 如何使用GSON解析JSON數據
- Gson之toJson和fromJson方法的具體使用
- Java 泛型 Generic機制實例詳解