Считывает дату как целое число из массива из json и сопоставляет с POJO как целое число

#java #jackson #mapping #pojo

#java #джексон #сопоставление #pojo

Вопрос:

Я получаю json из rest api и хочу сохранить данные в списке POJO. Ниже приведен код для того же:

 public List<myObject> mapper(){

    String myObjectData= restClient.getAllOriginal("myObject");

    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    objectMapper.configure(DeserializationConfig.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);

    
    List<CommitmentPojo> resultDto = null;

    try
    {

        Map<String, List<MyObject>> root = mapper.readValue(jsonString, new TypeReference<Map<String, List<MyObject>>>() {});
        List<MyObject> objects = root.get("myObject");
        
    }
    catch (JsonParseException e)
    {
        e.printStackTrace();
    }
    catch (JsonMappingException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return resultDto;
}
  

Метод, который получает строку из rest api:

 public  String getAllOriginal(String resourcePath) {
       // Objects.requireNonNull(this.baseUri, "target cannot be null");
        return this.client
                .target("http://comtsrvc.ny.qa.flx.nimbus.gs.com:3802/v2/")
                .path(resourcePath)
                .request(MediaType.APPLICATION_JSON_TYPE)
                .cookie("mySSO", getCookie())
                .get()
                .readEntity(String.class);
    }
  

Ниже приведен мой json:

 {
  
  "myObject" : [ {
    "key" : {
      "srcSys" : "REPO_1",
      "srcSysRef" : "20200909_1911_1"
    },
    "productData" : {
      "id" : null,
      "number" : null,
      "isn" : null,
      "productId" : null,
      "productAdditionalData" : {
        "assetClassTree" : "UNCLASSIFIED",
        "description" : "UNCLASSIFIED",
        "productTypeData" : {
          "productType" : "UNCLASSIFIED",
          "productGroup" : "UNCLASSIFIED"
        }
      }
    },
    "state" : "OPEN",
    "type" : "01"
  }, {
    "key" : {
      "srcSys" : "REPO_2",
      "srcSysRef" : "20200403_3892_1"
    },
    "productData" : {
      "id" : "1",
      "number" : "11",
      "isn" : "null",
      "productId" : 1234,
      "productAdditionalData" : {
        "assetClassTree" : "xyz",
        "description" : "abc",
        "productTypeData" : {
          "productType" : "UNCLASSIFIED",
          "productGroup" : "UNCLASSIFIED"
        }
      }
    },
    "state" : "OPEN",
    "startDate" : [2020, 9, 22],
    "endDate" : [2020, 9, 24],
    "tradAcctType" : "01"
  } ]
  }
  

При условии, что я не могу изменить существующий POJO (если и до тех пор, пока это не потребуется), поскольку для этого потребуется много модификаций.
Я не понимаю, как получить доступ к дате из массива и сопоставить ее с POJO, где StartDate имеет целочисленный тип данных.

Комментарии:

1. В вашем POJO StartDate это тип int или int[]? В частности, как вы хотите сопоставить [2020, 9, 22] с int?

2. В моем POJO начальная дата равна int . Я хочу сопоставить его как 20200922

3. Не используйте 20200922 (двоичный код 10011010 00011110 111011010) для представления даты, это не имеет смысла. Используйте LocalDate . Форматирование вашего LocalDate в строку, например 20200922 , для отображения, передачи данных, хранения или любых других целей, тривиально, поэтому подождите, пока вам это понадобится, прежде чем делать это.

Ответ №1:

Возможно ли определить конструктор с аннотацией @JsonCreator в POJO, а затем проанализировать список для полей даты в json?

Что-то похожее на это.

Test.java

 import java.util.List;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;

public class Test {
    private String state;
    private int startDate;
    private int endDate;

    @JsonCreator
    public Test(@JsonProperty("startDate") List<Integer> startDate,
            @JsonProperty("endDate") List<Integer> endDate) {
        StringBuilder stringBuilder = new StringBuilder();
        for (Integer value : startDate) {
            stringBuilder.append(value);
        }
        this.startDate = Integer.parseInt(stringBuilder.toString());
        stringBuilder.setLength(0);
        for (Integer value : endDate) {
            stringBuilder.append(value);
        }
        this.endDate = Integer.parseInt(stringBuilder.toString());
    }

    /**
     * @return the state
     */
    public String getState() {
        return state;
    }

    /**
     * @param state
     *            the state to set
     */
    public void setState(String state) {
        this.state = state;
    }

    /**
     * @return the startDate
     */
    public int getStartDate() {
        return startDate;
    }

    /**
     * @param startDate
     *            the startDate to set
     */
    public void setStartDate(int startDate) {
        this.startDate = startDate;
    }

    /**
     * @return the endDate
     */
    public int getEndDate() {
        return endDate;
    }

    /**
     * @param endDate
     *            the endDate to set
     */
    public void setEndDate(int endDate) {
        this.endDate = endDate;
    }
}
  

Main.java

 import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

public class Main {
    public static void main(String[] args) {
        String json = "{"state" : "OPEN", "startDate" : [2020, 9, 22], "endDate" : [2020, 9, 24]}";

        ObjectMapper mapper = new ObjectMapper();
        try {
            Test test = mapper.readValue(json, Test.class);
            System.out.println(test.getStartDate()   "   "   test.getEndDate()
                      "   "   test.getState());
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
    }
}
  

Вывод:

 2020922   2020924   OPEN
  

Если обновление класса POJO невозможно, существует другой альтернативный способ реализации пользовательского десериализатора. Где вы можете реализовать аналогичную логику преобразования.

Пользовательский подход к десериализации

CustomTest.java

 public class CustomTest {
    private String state;
    private int startDate;
    private int endDate;

    /**
     * @return the state
     */
    public String getState() {
        return state;
    }

    /**
     * @param state
     *            the state to set
     */
    public void setState(String state) {
        this.state = state;
    }

    /**
     * @return the startDate
     */
    public int getStartDate() {
        return startDate;
    }

    /**
     * @param startDate
     *            the startDate to set
     */
    public void setStartDate(int startDate) {
        this.startDate = startDate;
    }

    /**
     * @return the endDate
     */
    public int getEndDate() {
        return endDate;
    }

    /**
     * @param endDate
     *            the endDate to set
     */
    public void setEndDate(int endDate) {
        this.endDate = endDate;
    }
}
  

CustomTestDeserializer.java

 import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;

public class CustomTestDeserializer extends StdDeserializer<CustomTest> {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    public CustomTestDeserializer() {
        this(null);
    }

    protected CustomTestDeserializer(Class<?> vc) {
        super(vc);
    }

    @Override
    public CustomTest deserialize(JsonParser jp, DeserializationContext dCtxt)
            throws IOException, JsonProcessingException {
        JsonNode node = jp.getCodec().readTree(jp);
        String state = node.get("state").asText();
        ObjectMapper mapper = new ObjectMapper();
        List<Integer> startDateValue = mapper.convertValue(
                node.get("startDate"), List.class);
        StringBuilder stringBuilder = new StringBuilder();
        for (Integer value : startDateValue) {
            stringBuilder.append(value);
        }
        int startDate = Integer.parseInt(stringBuilder.toString());

        List<Integer> endDateValue = mapper.convertValue(node.get("endDate"),
                List.class);
        stringBuilder.setLength(0);
        for (Integer value : endDateValue) {
            stringBuilder.append(value);
        }
        int endDate = Integer.parseInt(stringBuilder.toString());

        CustomTest customTest = new CustomTest();
        customTest.setEndDate(endDate);
        customTest.setStartDate(startDate);
        customTest.setState(state);
        return customTest;
    }
}
  

CustomTestClient.java

 import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;

public class CustomTestClient {
    public static void main(String[] args) {
        String json = "{"state" : "OPEN", "startDate" : [2020, 9, 22], "endDate" : [2020, 9, 24]}";

        ObjectMapper mapper = new ObjectMapper();
        SimpleModule module = new SimpleModule();
        module.addDeserializer(CustomTest.class, new CustomTestDeserializer());
        mapper.registerModule(module);

        try {
            CustomTest customTest = mapper.readValue(json, CustomTest.class);
            System.out.println(customTest.getStartDate()   "   "
                      customTest.getEndDate()   "   "   customTest.getState());
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
    }
}
  

Вывод:

 2020922   2020924   OPEN
  

ПРИМЕЧАНИЕ: Пожалуйста, не забудьте правильно реализовать обработку null.

Предполагая, что вы не хотите изменять POJO, следовательно, вместо аннотации @JsonDeserialize на уровне класса bean, необходимо зарегистрировать этот пользовательский десериализатор в клиентском коде.

Комментарии:

1. Это хорошо известно и полезно ( 1). Только не сохраняйте даты как int в объекте. Используйте LocalDate и присваивайте this.startDate = LocalDate.of(startDate.get(0), startDate.get(1), startDate.get(2)); (и аналогично для даты окончания, как вы, возможно, догадались) (в то же время это позволяет избежать форматирования в строку и ее обратного анализа).