为 Jackson 自定义序列化对象的 JSON 格式
伴随着 Play1, 我们原来使用的 JSON 库是 Gson. 回忆下 Gson 是怎么自定义序列化对象的 JSON 格式,大概是这样子的
GsonBuilder()..registerTypeHierarchyAdapter(Cat.class, new Cat());
然后 Cat 需要实现 JsonSerializer 的 serialize() 方法。
来到了 Play2 中,JSON 库变成了 Jackson,那么 Jackson 该如何为对象自定义 JSON 格式呢?
例如,默认时 Jackson 对 Map 类型输出的是一个 JSON 对象
Map("key1"->"value1", "key2"->"value2") 转换成 JSON 是 {"key1":"value1", "key2":"value2"}
当为适应某些客户端,对于 LinkedHashMap 类型,我们想要输出的是一个有序的 JSON 数组: [{"key1":"value1"},{"key2":"value2"}]
我们就应该自定义某些 Map 的序列化格式,实现方法有两种,addSerializer 和 @JsonSerialize,不管哪种方式都需事先具体化 JsonSerializer 类,并实现它的 serialize 抽象方法
所以我先来实现一个能序列化 Map 的 JsonArrayMapSerializer 类
上面调用了 JsonGenerator 的 writeXxx() 方法来输出 JSON 格式
接着看两种实现方式
1. addSerializer() 方式
我采用了 Scala 来书写测试代码, 贴代码也有点问题,所以用图片代替
测试结果:
2. @JsonSerialize 注解方式
看下注解 @JsonSerialize 的定义
@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.TYPE, ElementType.PARAMETER})
它可以作用在注解,方法,字段,类型和参数上。我们举两个例子,分别是对类型和字段使用此注解
1)自定义的 JsonArrayMap 类型
2) 作用在字段上
用测试用例来验证下:
测试结果
可以进一步考虑让 @JsonSerialize 应用在别处,如方法参数,getter 方法上。
永久链接 https://yanbin.blog/jackson-custom-serialize-json-format/, 来自 隔叶黄莺 Yanbin's Blog
[版权声明]
本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。
GsonBuilder()..registerTypeHierarchyAdapter(Cat.class, new Cat());
然后 Cat 需要实现 JsonSerializer 的 serialize() 方法。
来到了 Play2 中,JSON 库变成了 Jackson,那么 Jackson 该如何为对象自定义 JSON 格式呢?
例如,默认时 Jackson 对 Map 类型输出的是一个 JSON 对象
Map("key1"->"value1", "key2"->"value2") 转换成 JSON 是 {"key1":"value1", "key2":"value2"}
当为适应某些客户端,对于 LinkedHashMap 类型,我们想要输出的是一个有序的 JSON 数组: [{"key1":"value1"},{"key2":"value2"}]
我们就应该自定义某些 Map 的序列化格式,实现方法有两种,addSerializer 和 @JsonSerialize,不管哪种方式都需事先具体化 JsonSerializer 类,并实现它的 serialize 抽象方法
所以我先来实现一个能序列化 Map 的 JsonArrayMapSerializer 类
1package cc.unmi.serialization;
2
3import com.fasterxml.jackson.core.*;
4import com.fasterxml.jackson.databind.*;
5
6import java.io.IOException;
7import java.util.Map;
8
9public class JsonArrayMapSerializer extends JsonSerializer<Map<?, ?>> {
10
11 @Override
12 public void serialize(Map<?, ?> value, JsonGenerator jgen, SerializerProvider provider)
13 throws IOException, JsonProcessingException {
14 jgen.writeStartArray();
15 for(Object key: value.keySet()) {
16 jgen.writeStartObject();
17 jgen.writeObjectField(key.toString(), value.get(key));
18 jgen.writeEndObject();
19 }
20 jgen.writeEndArray();
21 }
22}上面调用了 JsonGenerator 的 writeXxx() 方法来输出 JSON 格式
接着看两种实现方式
1. addSerializer() 方式
我采用了 Scala 来书写测试代码, 贴代码也有点问题,所以用图片代替
测试结果:
2. @JsonSerialize 注解方式看下注解 @JsonSerialize 的定义
@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.TYPE, ElementType.PARAMETER})
它可以作用在注解,方法,字段,类型和参数上。我们举两个例子,分别是对类型和字段使用此注解
1)自定义的 JsonArrayMap 类型
1package cc.unmi.serialization;
2
3import com.fasterxml.jackson.databind.annotation.JsonSerialize;
4import java.util.LinkedHashMap;
5
6@JsonSerialize(using = JsonArrayMapSerializer.class)
7public class JsonArrayMap<K, V> extends LinkedHashMap<K, V>{
8
9}2) 作用在字段上
1val map = new java.util.HashMap[String, String]
2map.put("key1", "value1")
3map.put("key2", "value2")
4
5val obj = new Object {
6 @JsonSerialize(using = classOf[JsonArrayMapSerializer])
7 val attr = map
8}用测试用例来验证下:
1package cc.unmi.serialization
2
3import com.fasterxml.jackson.databind.{PropertyNamingStrategy, ObjectMapper}
4import utilities.JsonArrayMap
5import com.fasterxml.jackson.databind.annotation.JsonSerialize
6import org.scalatest.{MustMatchers, WordSpec}
7
8class JsonArrayMapSerializerTest extends WordSpec with MustMatchers {
9
10 "JsonArrayMapSerializer#serialize" should {
11
12 val jsonSerializer: ObjectMapper = new ObjectMapper()
13 .setPropertyNamingStrategy(PropertyNamingStrategy.PASCAL_CASE_TO_CAMEL_CASE)
14
15 "generate a JsonArrayMap as JSON array format" in {
16 val map = new JsonArrayMap[String, String]
17 map.put("key1", "value1")
18 map.put("key2", "value2")
19
20 val jsonString = jsonSerializer.writeValueAsString(map)
21 jsonString mustBe """[{"key1":"value1"},{"key2":"value2"}]"""
22 }
23
24 "write Map to json array if annotated with @JsonSerialize(using = classOf[JsonArrayMapSerializer]) " in
25 {
26 val obj = new {
27 @JsonSerialize(using = classOf[JsonArrayMapSerializer])
28 val field = new java.util.HashMap[String, String]
29 field.put("key1", "value1")
30 field.put("key2", "value2")
31 }
32
33 val jsonString = jsonSerializer.writeValueAsString(obj)
34 jsonString mustBe """{"Field":[{"key2":"value2"},{"key1":"value1"}]}"""
35 }
36 }
37}测试结果
可以进一步考虑让 @JsonSerialize 应用在别处,如方法参数,getter 方法上。
永久链接 https://yanbin.blog/jackson-custom-serialize-json-format/, 来自 隔叶黄莺 Yanbin's Blog[版权声明]
本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。