簡體   English   中英

使用Jackson在Java中使用JSON序列化時遇到問題

[英]Trouble serializing with to JSON in Java using Jackson

早上好家伙!

我有一個JSON字符串,看起來像:

{
   "StatusCode":0,
   "Message":null,
   "ExecutionTime":0,
   "ResponseData":[
        {"Name":"name1","SiteId":"1234","Type":"Type1","X":"1234567","Y":"123456"},
        {"Name":"Name2","SiteId":"2134","Type":"Type2","X":"1234567","Y":"1234567"},
        {"Name":"Name3","SiteId":"3241","Type":"Type3","X":"1234567","Y":"1234567"},
        {"Name":"Name4","SiteId":"4123","Type":"Type4","X":"123456","Y":"123456"}
    ]
}

我想創建一個可以檢索XY值的對象。

我一直在嘗試使用Jackson序列化JSON字符串,但沒有成功。 我為傑克遜創建了兩個額外的課程。 頂層的一個類, StatusCodeMessageExecutionTimeResponseData看起來像

public class PL {
private Long statusCode;
private String executionTime;
private String message;
private ResponseData responseData;
public PL(){
}

public void setStatusCode(Long statusCode){
  this.statusCode = statusCode;
}

public Long getStatusCode(){
  return this.statusCode;
}

public void setExecutionTime(String executionTime){
  this.executionTime = executionTime;
}
public String getExecutionTime(){
  return this.executionTime;
}

public void setMessage(String message){
  this.message = message;
}
public String getMessage(){
  return this.message;
}

public void setResponseData(ResponseData responseData){
  this.responseData = responseData;
}
public ResponseData getResponseData(){
  return this.responseData;
}
}

ReponseData作為對象返回的地方,然后我有另一個用於序列化ResponseData類,看起來像

public class ResponseData {

private String name;
private String siteId;
private String type;
private String x;
private String y;

public ResponseData(){
}

public void setName(String name){
  this.name = name;
}
public String getName(){
  return this.name;
}

public void setSiteId(String siteId){
  this.siteId = siteId;
}
public String getSiteId(){
  return this.siteId;
}

public void setType(String type){
  this.type = type;
}
public String setType(){
  return this.type;
}

public void setX(String x){
  this.x = x;
}
public String getX(){
  return this.x;
}

public void setY(String y){
  this.y = y;
}
public String getY(){
  return this.y;
}
}

然后我創建一個ObjectMapper

private final static ObjectMapper mapper = new ObjectMapper();

並試着用這樣讀取值

ResponseData e = mapper.readValue(result.toString(), ResponseData.class);

並最終得到例外

com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException:無法識別的字段“StatusCode”(類MyClass.ResponseData),未標記為可忽略(5個已知屬性:“x”,“y”,“siteId”,“name”,“類型”])

好像它無法解析第一個條目StatusMessage 即使我刪除了第二個類,並且只嘗試解析前面的四個條目,我將ResponseData作為String返回,我仍然得到相同的異常。

首先,在PL你應該有一個List<ResponseData>而不是一個簡單的ResponseData屬性。 如您所見,在JSON中, ResponseData是一個數組"ResponseData":[...]因此它將被反序列化為List 列表的每個元素都是您定義的ResponseData對象。

然后你遇到了一個案例問題,你在類屬性中沒有大寫的JSON。 您可以使用@JsonProperty請參閱API )批注來解決此問題,方法如下:

class PL {
    @JsonProperty("StatusCode")
    private Long statusCode;
    @JsonProperty("ExecutionTime")
    private String executionTime;
    @JsonProperty("Message")
    private String message;
    @JsonProperty("ResponseData")
    private List<ResponseData> responseDatas;

    public PL(){
    }

    // getters/Setters  

}


class ResponseData {

    @JsonProperty("Name")
    private String name;
    @JsonProperty("SiteId")
    private String siteId;
    @JsonProperty("Type")
    private String type;
    @JsonProperty("X")
    private String x;
    @JsonProperty("Y")
    private String y;

    public ResponseData(){
    }

    // getters/Setters  

}

然后將您的JSON讀作PL對象,如下所示:

ObjectMapper mapper = new ObjectMapper();
PL pl = mapper.readValue(json, PL.class);
for(ResponseData rd : pl.getResponseDatas()) {
    System.out.println(rd.getX());
    System.out.println(rd.getY());
}

這輸出:

1234567
123456
1234567
1234567
1234567
1234567
123456
123456

這很簡單。 使用類的組合定義響應結構。 不幸的是在JSON中使用大寫字段,開箱即用需要Java DTO中的大寫字段名稱。 通過在ObjectMapper上使用ACCEPT_CASE_INSENSITIVE_PROPERTIES修飾符或通過注釋具有相應名稱的字段,可以輕松地將這些名稱映射到傳統的低案例名稱。 我更喜歡ObjectMapper上的一個屬性,因為它使DTO獨立於序列化代碼,並且這種技術在下面的測試中使用(測試是綠色的):

import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;

public class TestDeserialization50386188 {

    public static class Response {

        public static class ResponseDataType {
            public String name;
            public String siteId;
            public String type;
            public long x;
            public long y;
        }

        public int statusCode;
        public String message;
        public long executionTime;
        public List<ResponseDataType> ResponseData = new ArrayList<>();
    }

    private static final String data = "{\"StatusCode\":0,\"Message\":null,\"ExecutionTime\":0,\"ResponseData\":[{\"Name\":\"name1\",\"SiteId\":\"1234\",\"Type\":\"Type1\",\"X\":\"1234567\",\"Y\":\"123456\"},{\"Name\":\"Name2\",\"SiteId\":\"2134\",\"Type\":\"Type2\",\"X\":\"1234567\",\"Y\":\"1234567\"},{\"Name\":\"Name3\",\"SiteId\":\"3241\",\"Type\":\"Type3\",\"X\":\"1234567\",\"Y\":\"1234567\"},{\"Name\":\"Name4\",\"SiteId\":\"4123\",\"Type\":\"Type4\",\"X\":\"123456\",\"Y\":\"123456\"}]}";

    @Test
    public void deserialize_response_withJackson_ok() throws IOException {
        ObjectMapper mapper = new ObjectMapper()
          .configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true);

        Response response = mapper.readValue(data, Response.class);

        assertEquals(4, response.ResponseData.size());
        assertEquals(1234567, response.ResponseData.get(2).x);
        assertEquals(1234567, response.ResponseData.get(2).y);
    }
}

你填寫在這個專用的GitHub倉庫上找到帶有可執行測試的項目。

Uncle Bob的“清潔代碼”一書並沒有真正推薦過度使用在Java中用於DTO的getter和setter,這是一個Response類。 如果你願意,你仍然可以用吸氣劑/固定劑對替換所有公共區域,但是清晰度會受到影響而質量沒有明顯增加。

使用List接收數組。

private Long statusCode;
private String executionTime;
private String message;
public List<ResponseDataType> ResponseData

它會自動完成所有事情。

暫無
暫無

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

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