这篇文章主要介绍了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。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程学习网。
本文标题为:Gson中@JsonAdater注解的几种方式总结
- value & 是什么意思?0xff 在 Java 中做什么? 2022-01-01
- C++ 和 Java 进程之间的共享内存 2022-01-01
- 从 finally 块返回时 Java 的奇怪行为 2022-01-01
- Safepoint+stats 日志,输出 JDK12 中没有 vmop 操作 2022-01-01
- 如何使用WebFilter实现授权头检查 2022-01-01
- 将log4j 1.2配置转换为log4j 2配置 2022-01-01
- Spring Boot连接到使用仲裁器运行的MongoDB副本集 2022-01-01
- Java包名称中单词分隔符的约定是什么? 2022-01-01
- Eclipse 插件更新错误日志在哪里? 2022-01-01
- Jersey REST 客户端:发布多部分数据 2022-01-01