Проблема сериализации с JSON в Java с использованием Джексона - PullRequest
0 голосов
/ 17 мая 2018

Доброе утро, ребята!

У меня есть строки 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"}
    ]
}

Я хочу создать объект, в котором я могу получить значения X и Y.

Я пытался использовать Джексона для сериализации строки JSON, но безуспешно. Я создал два дополнительных класса для использования Джексоном. Один класс для верхнего слоя, StatusCode, Message, ExecutionTime и ResponseData, который выглядит как

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» "," type "])

как будто он не может разобрать первую запись, StatusMessage. Даже если я удаляю второй класс и пытаюсь проанализировать только первые четыре записи, в которых я возвращаю ResponseData как String, я все равно получаю то же исключение.

Ответы [ 3 ]

0 голосов
/ 17 мая 2018

Используйте список для получения массивов.

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

и все будет сделано автоматически.

0 голосов
/ 17 мая 2018

Для начала, в 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
0 голосов
/ 17 мая 2018

Это довольно просто.Определите свою структуру ответа, используя композицию классов.К сожалению, в JSON используются заглавные поля, для которых из коробки требуются заглавные имена полей в Java DTO.Тем не менее, их можно легко сопоставить с обычными именами в нижнем регистре либо с помощью модификатора ACCEPT_CASE_INSENSITIVE_PROPERTIES в ObjectMapper, либо с помощью аннотирования полей с соответствующими именами.Я предпочитаю свойство на 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 .

Книга «Чистый код» , написанная дядей Бобом, на самом деле не рекомендует чрезмерное использование геттеров и сеттеров, столь распространенных в Javaдля DTO, которые Response класс.Тем не менее, вы можете заменить все открытые поля парами геттер / сеттер, если хотите, но ясность пострадает без очевидного увеличения качества.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...