使用Jackon进行JSON反序列化

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());
  }
}
Debug截图

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)

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。
禁止转载,如需转载请通过简信或评论联系作者。

推荐阅读更多精彩内容