使用Jackon進(jìn)行JSON反序列化

Jackson是當(dāng)前比較廣泛的,用來(lái)序列化和反序列化JSON的Java的開(kāi)源框架。本文主要介紹Jackson反序列化的簡(jiǎn)單使用(序列化以后用到的話(huà)會(huì)更新),其他比較深層的剖析請(qǐng)查閱相關(guān)文檔。

Jackson的github主頁(yè)( https://github.com/FasterXML/jackson-databind )有很多優(yōu)秀的文檔,本文大部分參考其中Baeldung的教程( https://www.baeldung.com/jackson ),可以通過(guò)郵箱注冊(cè)免費(fèi)獲取。

本文代碼和使用的教程可在文末網(wǎng)盤(pán)鏈接獲取。

1. 準(zhǔn)備工作

使用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倉(cāng)庫(kù)搜索網(wǎng)站:mvnrepository https://mvnrepository.com/

2. 反序列化注解

  • @JsonCreator結(jié)合@JsonProperty序列化

  • @JsonAnySetter可以將Map等靈活的內(nèi)容作為標(biāo)準(zhǔn)的屬性

  • @JsonSetter@JsonProperty的替代,它注解在set方法

2.1 @JsonCreator@JsonProperty

根據(jù)test1.json創(chuàng)建BeanWithCreator類(lèi)的對(duì)象,內(nèi)容如下(src/test/recources/org/example/deserialization/test1.json):

{
  "id": 1,
  "theName": "My bean"
}

@JsonCreator注解構(gòu)造器,@JsonProperty(x)后面的形參標(biāo)記json中x的value,x標(biāo)記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;
    }
}

測(cè)試代碼如下,注意其中創(chuàng)建對(duì)象的方法。

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 內(nèi)容:

{
  "name": "My bean",
  "attr2": "val2",
  "attr1": "val1"
}

ExtendableBean類(lèi):

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;
    }
}

測(cè)試方法:

    @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內(nèi)容:

{
  "id": 1,
  "name": "My bean"
}

MyBean類(lèi):

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方法,后面不接參數(shù)默認(rèn)標(biāo)記setter方法(如setId)去除set前綴后(id)的成員變量,其中包括將首字母變小寫(xiě);如果后面接形參就標(biāo)記該方法給形參的成員變量設(shè)值。

測(cè)試方法:

    @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,稱(chēng)為ObjectMapper將Java對(duì)象映射到JSON(序列化),或?qū)SON映射到對(duì)象(反序列化)。

3.1 JSON到Java對(duì)象

test4.json內(nèi)容:

{
  "color": "Black",
  "type": "BMW"
}

test5.json內(nèi)容:

{
  "color": "yellow",
  "type": "renault"
}

Car類(lèi):

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;
    }
}

測(cè)試方法:

    @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

測(cè)試方法:

    @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. 反序列化示例

給一份代碼添加功能時(shí)用到JSON反序列化,下面簡(jiǎn)單介紹。

根據(jù)JSON反序列化,涉及自定義類(lèi)、Map等。代碼中有些注解,看名字基本可以知道功能。

4.1 創(chuàng)建ReachabilityErrorBasicInfo類(lèi)

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類(lèi):

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 涉及的其他類(lèi)

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 測(cè)試方法

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對(duì)test6.json進(jìn)行反序列化
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"
  ]
}

對(duì)應(yīng)的部分方法代碼:

  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 (訪(fǎng)問(wèn)密碼 : 5opx2q)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
禁止轉(zhuǎn)載,如需轉(zhuǎn)載請(qǐng)通過(guò)簡(jiǎn)信或評(píng)論聯(lián)系作者。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容