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