动态类型绑定
参考链接:https://www.icode9.com/content-1-198969.html
基类:
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.transform.module.deviceserver.snapshot.*;
@JsonTypeInfo(property = "deviceType", use = JsonTypeInfo.Id.NAME)
@JsonSubTypes({
@JsonSubTypes.Type(value = LedSnapshot.class, name = "led"),
@JsonSubTypes.Type(value = TvSnapshot.class, name = "tv")
})
public class BaseSnapshot {
}
子类:
public class LedSnapshot extends BaseSnapshot {
private boolean power;
private int mode;
public boolean getPower() {
return power;
}
public void setPower(boolean power) {
this.power = power;
}
public int getMode() {
return mode;
}
public void setMode(int mode) {
this.mode = mode;
}
}
支持JDK8日期时间类型
添加依赖:
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.datatype/jackson-datatype-jsr310 -->
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.10.0</version>
</dependency>
加载模块:
ObjectMapper mapper = new ObjectMapper();
// 只加载JDK8时间模块
// mapper.registerModule(new JavaTimeModule());
// 自动发现并加载所有模块
mapper.findAndRegisterModules();
// 调用方法进行解析,例如下一行
// Config config = mapper.readValue(builder.toString(), Config.class);
对内层节点进行解析及绑定
格式化后的配置文件:
{
"test": {
"num1": 123,
"num2": 456
}
}
数据类:
public class TestData {
private int num1;
private int num2;
public int getNum1() {
return num1;
}
public void setNum1(int num1) {
this.num1 = num1;
}
public int getNum2() {
return num2;
}
public void setNum2(int num2) {
this.num2 = num2;
}
}
绑定代码:
String content = "{\"test\": {\"num1\": 123, \"num2\": 456}}";
ObjectMapper mapper = new ObjectMapper();
JsonNode node = mapper.readTree(content);
// 读取内层节点
node = node.get("test");
// 数据绑定
TestData data = mapper.treeToValue(node, TestData.class);
YAML支持
添加依赖:
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.dataformat/jackson-dataformat-yaml -->
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-yaml</artifactId>
<version>2.10.0</version>
</dependency>
示例代码:
String content = "";
ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
Config config = mapper.readValue(content, Config.class);
在反序列化中支持泛型
场景:HTTP响应的时候经常会在最顶层放一个通用的数据结构,然后其中某一项是业务数据。我们需要用一种通用且简洁的方法把数据反序列化出来,并且反序列化出的类型还需要方便使用。
数据结构
外层的通用结构
public class ResponseVo<T> {
private T data;
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
内层的业务结构
public class Device {
private String deviceId;
public String getDeviceId() {
return deviceId;
}
public void setDeviceId(String deviceId) {
this.deviceId = deviceId;
}
}
反序列化方法一:使用TypeReference
思路是实现TypeReference接口,将泛型类型放在TypeReference的泛型中。然后实例化该类的一个对象,把这个对象传入readValue方法中。
Tip: TypeReference实现类对象可以做成单例,避免每次反序列化都生成一次。
public class JacksonTest {
private ObjectMapper objectMapper;
public JacksonTest() {
this.objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
}
@Test
public void first() throws JsonProcessingException {
String json = "{\"data\": {\"deviceId\": \"132456\"}}";
ResponseVo<Device> vo = objectMapper.readValue(json,
new TypeReference<ResponseVo<Device>>(){});
System.out.println(objectMapper.writeValueAsString(vo));
}
}
反序列化方法二:使用TypeFactory生成JavaType
思路是使用TypeFactory的方法构造一个描述类型的JavaType对象,然后把JavaType对象传入readValue中。
Tip: JavaType对象也可以做成单例避免每次生成。
public class JacksonTest {
private ObjectMapper objectMapper;
public JacksonTest() {
this.objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
}
@Test
public void second() throws JsonProcessingException {
String json = "{\"data\": {\"deviceId\": \"132456\"}}";
ResponseVo<Device> vo = objectMapper.readValue(json,
new TypeReference<ResponseVo<Device>>(){});
System.out.println(objectMapper.writeValueAsString(vo));
TypeFactory factory = objectMapper.getTypeFactory();
ResponseVo<Device> vo = objectMapper.readValue(json, factory.constructParametricType(ResponseVo.class, Device.class));
System.out.println(objectMapper.writeValueAsString(vo));
}
}
不过TypeFactory使用起来不是那么直观易懂,而且方法注释也很不清晰。下面是我对方法进行测试后的一些猜测。
- constructArrayType:用于Java数组类型
- constructCollectionType:用于Collection子类
- constructMapType:用于Map类型
- constructParametricType:用于普通类的泛型
- constructGeneralizedType:用于有父类关系的(不太懂)
- constructSpecializedType:用于有子类关系的(不太懂)