Jackson是当前比较广泛的,用来序列化和反序列化JSON的Java的开源框架。本文主要介绍Jackson反序列化的简单使用(序列化以后用到的话会更新),其他比较深层的剖析请查阅相关文档。
Jackson的github主页( https://github.com/FasterXML/jackson-databind )有很多优秀的文档,本文大部分参考其中Baeldung的教程( https://www.baeldung.com/jackson ),可以通过邮箱注册免费获取。
本文代码和使用的教程可在文末网盘链接获取。
1. 准备工作
使用jdk8
Maven:
<properties>
...
<!-- Use the latest version whenever possible. -->
<jackson.version>2.12.4</jackson.version>
...
</properties>
<dependencies>
...
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
...
</dependencies>
Maven仓库搜索网站:mvnrepository https://mvnrepository.com/
2. 反序列化注解
@JsonCreator
结合@JsonProperty
序列化@JsonAnySetter
可以将Map等灵活的内容作为标准的属性@JsonSetter
是@JsonProperty
的替代,它注解在set方法
2.1 @JsonCreator
和@JsonProperty
根据test1.json创建BeanWithCreator
类的对象,内容如下(src/test/recources/org/example/deserialization/test1.json):
{
"id": 1,
"theName": "My bean"
}
@JsonCreator
注解构造器,@JsonProperty(x)
后面的形参标记json中x的value,x标记json文件中的key为x
package org.example.deserialization;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
public class BeanWithCreator {
public int id;
public String name;
@JsonCreator
public BeanWithCreator(
@JsonProperty("id") int id,
@JsonProperty("theName") String name) {
this.id = id;
this.name = name;
}
}
测试代码如下,注意其中创建对象的方法。
package org.example.deserialization;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;
import java.io.File;
import java.io.IOException;
import static org.junit.Assert.assertEquals;
public class TestDeserialization {
@Test
public void whenDeserializingUsingJsonCreator_thenCorrect() throws IOException {
BeanWithCreator bean = new ObjectMapper().
readerFor(BeanWithCreator.class).
readValue(new File("src/test/recources/org/example/deserialization/test1.json"));
assertEquals(1, bean.id);
assertEquals("My bean", bean.name);
}
}
2.2 @JsonAnySetter
test2.json 内容:
{
"name": "My bean",
"attr2": "val2",
"attr1": "val1"
}
ExtendableBean
类:
public class ExtendableBean {
public String name;
private Map<String, String> properties;
public ExtendableBean() {
this.name = null;
this.properties = new HashMap<>();
}
@JsonAnySetter
public void add(String key, String value) {
properties.put(key, value);
}
public Map<String, String> getProperties() {
return properties;
}
}
测试方法:
@Test
public void whenDeserializingUsingJsonAnySetter_thenCorrect() throws IOException {
ExtendableBean bean = new ObjectMapper().
readerFor(ExtendableBean.class).
readValue(new File("src/test/recources/org/example/deserialization/test2.json"));
assertEquals("My bean", bean.name);
assertEquals("val2", bean.getProperties().get("attr2"));
}
2.2 @JsonSetter
json内容:
{
"id": 1,
"name": "My bean"
}
MyBean
类:
public class MyBean {
public int id;
public String name;
@JsonSetter
public void setId(int id) {
this.id = id;
}
@JsonSetter("name")
public void setTheName(String name) {
this.name = name;
}
}
@JsonSetter
注解setter方法,后面不接参数默认标记setter方法(如setId)去除set前缀后(id)的成员变量,其中包括将首字母变小写;如果后面接形参就标记该方法给形参的成员变量设值。
测试方法:
@Test
public void whenDeserializingUsingJsonSetter_thenCorrect() throws IOException {
MyBean bean = new ObjectMapper().
readerFor(MyBean.class).
readValue(new File("src/test/recources/org/example/deserialization/test3.json"));
assertEquals(1, bean.id);
assertEquals("My bean", bean.name);
}
3 ObjectMapper反序列化
ObjectMapper
是Jackon常用的API,称为ObjectMapper
将Java对象映射到JSON(序列化),或将JSON映射到对象(反序列化)。
3.1 JSON到Java对象
test4.json内容:
{
"color": "Black",
"type": "BMW"
}
test5.json内容:
{
"color": "yellow",
"type": "renault"
}
Car
类:
public class Car {
private String color;
private String type;
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
测试方法:
@Test
public void TestCarWithObjectMapper() throws IOException {
File input = new File("src/test/recources/org/example/deserialization/test4.json");
File newInput = new File("src/test/recources/org/example/deserialization/test5.json");
ObjectMapper objectMapper = new ObjectMapper();
Car car = objectMapper.readValue(input, Car.class);
assertEquals("Black", car.getColor());
assertEquals("BMW", car.getType());
car = objectMapper.readValue(newInput, Car.class);
assertEquals("yellow", car.getColor());
assertEquals("renault", car.getType());
}
3.2 JSON到Jsckson JsonNode
测试方法:
@Test
public void TestJsonToJsonNode() throws IOException {
File input = new File("src/test/recources/org/example/deserialization/test4.json");
ObjectMapper objectMapper = new ObjectMapper();
JsonNode jsonNode = objectMapper.readTree(input);
assertEquals("Black", jsonNode.get("color").asText());
}
4. 反序列化示例
给一份代码添加功能时用到JSON反序列化,下面简单介绍。
根据JSON反序列化,涉及自定义类、Map等。代码中有些注解,看名字基本可以知道功能。
4.1 创建ReachabilityErrorBasicInfo
类
error.json
{
"type": "reachability",
"srcIps": "192.168.1.1",
"dstIps": "192.168.2.1",
"srcNodes": "R1A",
"dstNodes": "R2B",
"trace": {
"FastEthernet0/0": {
"nodeName": "R2B",
"status": "final",
"nextNodes": {
"Loopback0": {
"nodeName": "Subnet U",
"status": "subnet"
}
}
}
}
}
ReachabilityErrorBasicInfo
类:
package org.example;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import java.util.Map;
@ParametersAreNonnullByDefault
public class ReachabilityErrorBasicInfo {
private static final String JSON_ERROR_TYPE = "type";
private static final String JSON_SRC_IPS = "srcIps";
private static final String JSON_DST_IPS = "dstIps";
private static final String JSON_SRC_NODES = "srcNodes";
private static final String JSON_DST_NODES = "dstNodes";
private static final String JSON_TRACE = "trace";
private final ErrorType _errorType;
private final String _srcIps;
private final String _dstIps;
private final String _srcNodes;
private final String _dstNodes;
@Nullable
private final Map<String, BasicNode> _trace;
@JsonCreator
private static ReachabilityErrorBasicInfo create(
@JsonProperty(JSON_ERROR_TYPE) String errorType,
@JsonProperty(JSON_SRC_IPS) String srcIps,
@JsonProperty(JSON_DST_IPS) String dstIps,
@JsonProperty(JSON_SRC_NODES) String srcNodes,
@JsonProperty(JSON_DST_NODES) String dstNodes,
@Nullable @JsonProperty(JSON_TRACE) Map<String, BasicNode> trace) {
return new ReachabilityErrorBasicInfo(errorType, srcIps, dstIps, srcNodes, dstNodes, trace);
}
public ReachabilityErrorBasicInfo(
String errorType,
String srcIps,
String dstIps,
String srcNodes,
String dstNodes,
@Nullable Map<String, BasicNode> trace) {
_errorType = ErrorType.valueOf(errorType.toUpperCase());
_srcIps = srcIps;
_dstIps = dstIps;
_srcNodes = srcNodes;
_dstNodes = dstNodes;
_trace = trace;
}
public ErrorType getErrorType() {
return _errorType;
}
public String getSrcIps() {
return _srcIps;
}
public String getDstIps() {
return _dstIps;
}
public String getSrcNodes() {
return _srcNodes;
}
public String getDstNodes() {
return _dstNodes;
}
@Nullable public Map<String, BasicNode> getTrace() {
return _trace;
}
}
4.2 涉及的其他类
package org.example;
public enum ErrorType {
REACHABILITY, UNKNOWN
}
package org.example;
public enum NodeStatus {
ORIGIN, FINAL, TRANSMIT, SUBNET
}
package org.example;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import java.util.Map;
@ParametersAreNonnullByDefault
public class BasicNode {
private static final String JSON_NODE_NAME = "nodeName";
private static final String JSON_STATUS = "status";
private static final String JSON_NEXT_NODES = "nextNodes";
private final String _nodeName;
private final NodeStatus _status;
// map<ifaceName, node>
@Nullable
private final Map<String, BasicNode> _nextNodes;
@JsonCreator
private static BasicNode create(
@JsonProperty(JSON_NODE_NAME) String nodeName,
@JsonProperty(JSON_STATUS) String status,
@Nullable @JsonProperty(JSON_NEXT_NODES) Map<String, BasicNode> nextNodes) {
return new BasicNode(nodeName, status, nextNodes);
}
public BasicNode(String nodeName, String status) {
this(nodeName, status, null);
}
public BasicNode(String nodeName, String status, @Nullable Map<String, BasicNode> nextNodes) {
_nodeName = nodeName;
_status = NodeStatus.valueOf(status.toUpperCase());
_nextNodes = nextNodes;
}
public String getNodeName() {
return _nodeName;
}
public NodeStatus getStatus() {
return _status;
}
@Nullable public Map<String, BasicNode> getNextNodes() {
return _nextNodes;
}
}
4.3 测试方法
package org.example;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;
import java.io.File;
import java.io.IOException;
import static org.junit.Assert.assertEquals;
public class ReachabilityErrorBasicInfoTest {
@Test
public void testReadErrorInfoFromJson() {
File file = new File("src/test/java/recources/org/example/error.json");
ObjectMapper objectMapper = new ObjectMapper();
ReachabilityErrorBasicInfo reachabilityErrorBasicInfo = null;
try {
reachabilityErrorBasicInfo = objectMapper.readValue(file, ReachabilityErrorBasicInfo.class);
} catch (IOException e) {
e.printStackTrace();
}
assert reachabilityErrorBasicInfo != null;
assertEquals(ErrorType.REACHABILITY, reachabilityErrorBasicInfo.getErrorType());
}
}
5. JsonNode反序列化
使用JsonNode对test6.json进行反序列化
test6.json:
{
"reachability1": {
"policyType": "reachability", "srcIps": "192.168.1.1", "dstIps": "192.168.2.1", "ingressNodeRegex": "R1A", "finalNodeRegex": "R2B",
"paths": [
[{"nodeName": "R1A", "ifacName": "FastEthernet0/0"}]
]
},
"reachability2": {
"policyType": "reachability", "srcIps": "192.168.1.1", "dstIps": "192.168.3.1", "ingressNodeRegex": "R1A", "finalNodeRegex": "R3C",
"paths": [
[{"nodeName": "R1A", "ifacName": "FastEthernet0/0"}, {"nodeName": "R2B", "ifacName": "FastEthernet1/0"}, {"nodeName": "R3C", "ifacName": "Loopback0"}]
]
},
"reachability3": {
"policyType": "reachability", "srcIps": "192.168.2.1", "dstIps": "192.168.3.1", "ingressNodeRegex": "R2B", "finalNodeRegex": "R3C",
"paths": [
[{"nodeName": "R2B", "ifacName": "FastEthernet1/0"}, {"nodeName": "R3C", "ifacName": "Loopback0"}]
]
},
"violation" : [
"reachability1"
]
}
对应的部分方法代码:
private void parse(String policyPath) {
File input = new File(policyPath);
ObjectMapper ob = new ObjectMapper();
try {
JsonNode js = ob.readTree(input);
Iterator<String> keyIt = js.fieldNames();
while (keyIt.hasNext()) {
String policyName = keyIt.next();
JsonNode policy = js.get(policyName);
if (JSON_VIOLATION.equals(policyName)) {
for (JsonNode js1:policy) {
violations.add(js1.asText());
}
} else {
String policyType = policy.get(JSON_POLICY_TYPE).asText();
String srcIps = policy.get(JSON_SRC_IPS) == null ? null : policy.get(JSON_SRC_IPS).asText();
String dstIps = policy.get(JSON_DST_IPS) == null ? null : policy.get(JSON_DST_IPS).asText();
String srcNodes = policy.get(JSON_INGRESS_NODE_REGEX) == null ? null : policy.get(JSON_INGRESS_NODE_REGEX).asText().toLowerCase();
String dstNodes = policy.get(JSON_FINAL_NODE_REGEX) == null ? null : policy.get(JSON_FINAL_NODE_REGEX).asText().toLowerCase();
List<Hop> fib = new ArrayList<>();
for (JsonNode jsHop: policy.get(JSON_FIB)) {
String nodeName = jsHop.get(JSON_NODE_NAME).asText().toLowerCase();
String ifacName = jsHop.get(JSON_IFAC_NAME).asText();
fib.add(new Hop(nodeName, ifacName));
}
policies.put(policyName, new ReachabilityPolicy(policyType, srcIps, dstIps, srcNodes, dstNodes, fib));
}
}
for (String vp: violations) {
policies.get(vp).setViolated(true);
}
} catch (IOException e) {
e.printStackTrace();
}
}
源码链接:
https://www.jianguoyun.com/p/DaVwpHQQ3-6pChj9rbAE (访问密码 : 5opx2q)