簡體   English   中英

當相同鍵的值的數據類型更改時,將JSON解析為POJO

[英]Parse JSON to POJO when data type of value for same key changes

我有下面的JSON

{      
    "date":{
        "year":2017,
        "month":3,
        "day":12
    },
    "name":"Jon",
    "message":{
        "product":"orange",
        "price":2000
    }
}

有時它如下JSON

 {      
   "date":2017312,
    "name":"Jon",
    "message":{
        "product":"orange",
        "price":2000
    }
  }

請注意,日期可以是JSON objectlong值。 如何將其解析為POJO 我正在使用Jackson庫。

一種方法是使用自定義解串器,您可以在其中邏輯檢查字段。(例如https://dzone.com/articles/custom-json-deserialization-with-jackson

字段長度可能是此處用來將其解析為元素的邏輯。

LOCALDATE的

您需要實現自定義反序列化程序,並使用JsonDeserialize注釋對給定字段進行注釋。 對於以下POJO模型:

class Pojo {

    @JsonDeserialize(using = LocalDateJsonDeserializer.class)
    private LocalDate date;
    private String name;
    private Message message;

    // getters, setters
}

class Message {

    private String product;
    private int price;

    // getters, setters
}

簡單的解串器實現如下所示:

class LocalDateJsonDeserializer extends JsonDeserializer<LocalDate> {

    @Override
    public LocalDate deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        if (p.currentToken() == JsonToken.START_OBJECT) {
            MapType mapType = ctxt.getTypeFactory().constructMapType(Map.class, String.class, Integer.class);
            JsonDeserializer<Object> mapDeserializer = ctxt.findRootValueDeserializer(mapType);
            Map<String, Integer> date = (Map<String, Integer>) mapDeserializer.deserialize(p, ctxt);

            return LocalDate.of(date.get("year"), date.get("month"), date.get("day"));
        } else if (p.currentToken() == JsonToken.VALUE_NUMBER_INT) {
            // You need to be really careful here. Date format is ambiguous
            // You should test it for all months and days
            String date = p.getValueAsString();
            int year = Integer.parseInt(date.substring(0, 4));
            // much better to use always two digits for month: `03` instead `3`
            int month = Integer.parseInt(date.substring(4, 5));
            int day = Integer.parseInt(date.substring(5, 7));

            return LocalDate.of(year, month, day);
        } else if (p.currentToken() == JsonToken.VALUE_NULL) {
            return null;
        }

        return null;
    }
}

簡單用法:

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import java.io.IOException;
import java.time.LocalDate;
import java.util.HashMap;
import java.util.Map;

public class Test {

    public static void main(String[] args) throws Exception {
        String json1 = "json 1 ...";
        String json2 = "json 2....";

        ObjectMapper mapper = new ObjectMapper();
        System.out.println(mapper.readValue(json1, Pojo.class));
        System.out.println(mapper.readValue(json2, Pojo.class));
    }
}

打印:

Pojo{date=2017-03-12, name='Jon', message=Message{product='orange', price=2000}}
Pojo{date=2017-03-12, name='Jon', message=Message{product='orange', price=2000}}

當然,您需要處理所有極端情況並改善錯誤處理,但是通常這就是我們應該如何對待可能具有不同格式的值的方式: JSON objectJSON arrayprimitives

LocalDateTime

對於LocalDateTime它的顯示方式應該類似。 我們需要創建POJO模型:

class Pojo {

    @JsonDeserialize(using = LocalDateTimeJsonDeserializer.class)
    private LocalDateTime time;
    private String name;
    private Message message;

    // getters, setters, toString
}

自定義反序列化器可能如下所示:

class LocalDateTimeJsonDeserializer extends JsonDeserializer<LocalDateTime> {

    @Override
    public LocalDateTime deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        if (p.currentToken() == JsonToken.START_OBJECT) {
            MapType mapType = ctxt.getTypeFactory().constructMapType(Map.class, String.class, Object.class);
            JsonDeserializer<Object> mapDeserializer = ctxt.findRootValueDeserializer(mapType);
            Map<String, Object> node = (Map<String, Object>) mapDeserializer.deserialize(p, ctxt);
            Map<String, Integer> date = (Map<String, Integer>) node.get("date");
            Map<String, Integer> time = (Map<String, Integer>) node.get("time");

            LocalDate localDate = LocalDate.of(date.get("year"), date.get("month"), date.get("day"));
            LocalTime localTime = LocalTime.of(time.get("hour"), time.get("minute"), time.get("second"), time.get("nano"));

            return LocalDateTime.of(localDate, localTime);
        } else if (p.currentToken() == JsonToken.VALUE_NUMBER_INT) {
            // You need to be really careful here. Date format is ambiguous
            // You should test it for all months and days
            String date = p.getValueAsString();
            // parse date string
            // ...

            return LocalDateTime.now();
        } else if (p.currentToken() == JsonToken.VALUE_NULL) {
            return null;
        }

        return null;
    }
}

反序列化的示例與LocalDate相同。 對於以下JSON有效負載:

{
  "time": {
    "date": {
      "year": 2019,
      "month": 3,
      "day": 29
    },
    "time": {
      "hour": 13,
      "minute": 21,
      "second": 20,
      "nano": 620000000
    }
  },
  "name": "Jon",
  "message": {
    "product": "orange",
    "price": 2000
  }
}

它應該打印:

Pojo{time=2019-03-29T13:21:20.620, name='Jon', message=Message{product='orange', price=2000}}

另外,看看涵蓋所有java.time.*類的JavaTimeModule模塊,並允許以標准方式進行序列化和反序列化,

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM