Java JSON使用

常用JSon包使用

GSON

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155

// 1. 属性重命名 @SerializedName 注解
@SerializedName
// 2. 备用属性名
@SerializedName(value = "emailAddress", alternate = {"email", "email_address"})
// 3. 返回值泛型
private Integer code;
private User data; // User
private List<User> data; // List<User>
Type userType = new TypeToken<Result<User>>(){}.getType();
Type userListType = new TypeToken<Result<List<User>>>(){}.getType();
// 4. Gson在默认情况下是不动导出值null的键的,需要的话写法,时间等处理
Gson gson = new GsonBuilder()
//序列化null
.serializeNulls()
// 设置日期时间格式,另有2个重载方法
// 在序列化和反序化时均生效
.setDateFormat("yyyy-MM-dd")
// 禁此序列化内部类
.disableInnerClassSerialization()
//生成不可执行的Json(多了 )]}' 这4个字符)
.generateNonExecutableJson()
//禁止转义html标签
.disableHtmlEscaping()
//格式化输出
.setPrettyPrinting()
// 5. @Expose,如果使用new Gson那么@Expose是无效的,可以通过这个来动态控制是否剔除确定元素
public class Category {
@Expose public int id; //@Expose 需要导出的字段上加上@Expose 注解,不导出的字段不加
@Expose public String name;
@Expose public List<Category> children;

//不需要序列化,所以不加 @Expose 注解,
//等价于 @Expose(deserialize = false,serialize = false)
public Category parent;
}
Gson gson = new GsonBuilder()
.excludeFieldsWithoutExposeAnnotation()
.create();
gson.toJson(category);

/**
* 6. 当前版本(GsonBuilder中设置的版本) 大于等于Since的值时该字段导出,小于Until的值时该该字段导出
*/
class SinceSample {
@Since(4)
public String since;
@Until(5)
public String until;
}

// 7. 指定修饰符的Field过滤
Gson gson = new GsonBuilder()
.excludeFieldsWithModifiers(Modifier.FINAL, Modifier.STATIC, Modifier.PRIVATE)
.create();

// 8. 自定义策略,比transient和@Expose强大,可以根据需要进行精确过滤
Gson gson = new GsonBuilder()
.addSerializationExclusionStrategy(new ExclusionStrategy() {
@Override
public boolean shouldSkipField(FieldAttributes f) {
// 这里作判断,决定要不要排除该字段,return true为排除
if ("finalField".equals(f.getName())) return true; //按字段名排除
Expose expose = f.getAnnotation(Expose.class);
if (expose != null && expose.deserialize() == false) return true; //按注解排除
return false;
}
@Override
public boolean shouldSkipClass(Class<?> clazz) {
// 直接排除某个类 ,return true为排除
return (clazz == int.class || clazz == Integer.class);
}
})
.create();

// 9. POJO与JSON的字段映射规则,GsonBuilder.setFieldNamingPolicy 方法与Gson提供的另一个枚举类FieldNamingPolicy配合使用,对Json key进行转换:UPPER_CAMEL_CASE、LOWER_CASE_WITH_DASHES
Gson gson = new GsonBuilder()
.setFieldNamingStrategy(new FieldNamingStrategy() {
@Override
public String translateName(Field f) {
//实现自己的规则
return null;
}
})
.create();

// 10. TypeAdapter 接管某种类型的序列化和反序列化过程,可以针对参数类型,参数值等进行处理,比如String转Integer

// 11. JsonSerializer与JsonDeserializer registerTypeAdapter 也可以用于对类型进行转换

// 12. TypeAdapterFactory

// 13. @JsonAdapter(UserTypeAdapter.class) 方便注册UserTypeAdapter

// 14. 同一个接口任何情况下不得改变返回类型,要么就不要返,要么就返空值。key通过registerTypeHierarchyAdapter进行处理,registerTypeAdapter处理、ReflectiveTypeAdapterFactory处理

/**
* generic (泛型) 完整Demo
*/
@Data
public class Test {

@Data
class DataBean{
private String name;
}

@Data
static class Result<T> {
Integer code;
String msg;
private T value;
}

public static void main(String[] rags) {
String jsonData = "{\n" +
" \"name\": \"test\"}";
Gson gson = new Gson();
DataBean bean = gson.fromJson(jsonData, DataBean.class);
System.out.println("bean name: " + bean.name); // 内部类可以直接访问
System.out.println("bean jsonStr: " + gson.toJson(bean));

Result<DataBean> foo = new Result<DataBean>();
foo.value = bean;
System.out.println("foo jsonStr: " + gson.toJson(foo));

String genericData = "{\"value\":{\"name\":\"test\"}}";
TypeToken<Result<DataBean>> typeToken = new TypeToken<Result<DataBean>>(){};
Result<DataBean> genericBean = gson.fromJson(genericData, typeToken.getType());
System.out.println("bean value1 : " + genericBean.getValue().getName());
System.out.println("bean value2 : " + gson.toJson(genericBean.getValue()));

TypeToken<Result<?>> typeToken2 = new TypeToken<Result<?>>(){};
Result<?> genericBean2 = gson.fromJson(genericData, typeToken2.getType()); // Foo<DataBean> 访问value.name的时候会报Map→DataBean错,上一个例子不会因为TypeToken指定类型了
System.out.println("bean type3 : " + genericBean2.value.getClass()); // 内部类可以直接访问 LinkedTreeMap
System.out.println("bean value3 : " + genericBean2.value); // 内部类可以直接访问

String jsonString = gson.toJson(genericBean2.value);
DataBean b = gson.fromJson(jsonString,DataBean.class); // gson把map转换成字符串再转成对象
System.out.println("bean value3 DataBean: " + b.name); // gson把map转换成字符串再转成对象
System.out.println("bean value3 : " + genericBean2.value);
System.out.println("bean value4 : " + gson.toJson(genericBean2));
}
}
// 执行结果
bean name: test
bean jsonStr: {"name":"test"}
foo jsonStr: {"value":{"name":"test"}}
bean value1 : test
bean value2 : {"name":"test"}
bean type3 : class com.google.gson.internal.LinkedTreeMap
bean value3 : {name=test}
bean value3 DataBean: test
bean value3 : {name=test}
bean value4 : {"value":{"name":"test"}}

序列化反序列化
java对象→json对象→json字符串→json对象→java对象

jackson

  • @JsonView 控制不同接口返回参数
    在查询列表请求中,不返回xxxx字段
    在获取用户详情中,返回xxxx字段

spring boot

  • @RequestBody
    • 后端@RequestBody注解对应的类在将HTTP的输入流(含请求体)装配到目标类(即:@RequestBody后面的类)时,会根据json字符 串中的key来匹配对应实体类的属性,如果匹配一致且json中的该key对应的值符合(或可转换为) 实体类的对应属性的类型要求时,会调用实体类的setter方法将值赋给该属性
    • json字符串中,如果value为””的话,后端对应属性如果是String类型的,那么接受到的就是””,如果是后端属性的类型是Integer、Double等类型,那么接收到的就是null。
    • json字符串中,如果value为null的话,后端对应收到的就是null。