Почему мой клиентский объект Jax-RS не десериализует списки JSON в этом HTTP-ответе, хотя это делает объект-маппер? - PullRequest
0 голосов
/ 30 мая 2019

Я начинаю писать клиент для REST API, и я начал с простого вызова, который возвращает относительно простой объект JSON: одну resultCode строку, одну message строку и список объектов. , Когда я сначала извлекаю объект в виде строки и декодирую его с помощью ObjectMapper, он просто отменяет маршализацию, включая список объектов. Однако, когда я получаю его с помощью объекта Client, он получает только свойства строки, а не список объектов. Я хотел бы смоделировать ответы API, которые более сложны, чем эта, но я не думаю, что было бы разумно, пока я не преодолею это препятствие.

Я пытался использовать аннотации, такие как создание метода setResultItems с аннотацией @JsonSetter. В моем первоначальном примере использовались методы получения и установки, но в примере, который я публикую, используются открытые поля для экономии места - результат тот же. Я также попытался заставить объект Client использовать тот же ObjectMapper, зарегистрировав для него JacksonJsonProvider. Одна вещь, которую я заметил, это то, что ObjectMapper вызывает конструктор, который сразу все настраивает, но Client требует конструктора без аргументов и устанавливает свойства после создания объекта.

Вот самая простая версия класса объекта ответа:

class ResponseObject {

    public String resultCode;
    public String message;
    public List<Map<String,String>> resultItems;

    ResponseObject() {
        System.out.println("Blank constructor called");
    }
    ResponseObject(
        @JsonProperty("resultItems") List<Map<String,String>> resultItems, 
        @JsonProperty("message") String message, 
        @JsonProperty("resultCode") String resultCode ) {
        System.out.println("Good constructor called");
        this.resultCode = resultCode;
        this.message = message;
        this.resultItems = resultItems;
    }

    private void print() {
        System.out.println("resultCode: " + resultCode);
        System.out.println("message: " + message);
        System.out.println("resultItems: " + resultItems.toString());
    }
}

Мое тестовое приложение запускает этот метод в try-catch:

    private static void doGetVariable() throws IOException {
        Client client = ClientBuilder.newClient();

        // hey this means the client should decode it the same way right?
        ObjectMapper mapper = new ObjectMapper();
        JacksonJsonProvider provider = new JacksonJsonProvider(mapper);
        client.register(provider);

        System.out.println("Getting string and deserializing it");
        String sresp = client.target(URL)
                .request(MediaType.APPLICATION_JSON)
                .get(String.class);
        System.out.println("string: "+sresp);
        ResponseObject resp1 = mapper.readValue(sresp, ResponseObject.class);
        resp1.print();
        System.out.flush();
        System.out.println("\nGetting object directly from the client");
        ResponseObject resp2 = client.target(URL)
                .request(MediaType.APPLICATION_JSON)
                .get(ResponseObject.class);
        resp2.print();
    }

Поскольку эти вещи, похоже, имеют значение, вот зависимости в моем файле pom.xml. Я должен был добавить Джерси, потому что если я не получу, я получу ClassNotFoundException, потому что он не может найти JerseyClientBuilder Я думаю, что это подсказка, но я не уверен, что это значит.

        <dependency>
            <groupId>javax.ws.rs</groupId>
            <artifactId>javax.ws.rs-api</artifactId>
            <version>2.1.1</version>
            <type>jar</type>
        </dependency>
        <dependency>
            <groupId>org.glassfish.jersey.ext.rx</groupId>
            <artifactId>jersey-rx-client</artifactId>
            <version>2.25.1</version>
        </dependency>
        <dependency>
            <groupId>org.glassfish.jersey.media</groupId>
            <artifactId>jersey-media-moxy</artifactId>
            <version>2.25.1</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.jaxrs</groupId>
            <artifactId>jackson-jaxrs-json-provider</artifactId>
            <version>2.9.9</version>
        </dependency>

Когда я запускаю его, вот вывод. Вы можете увидеть необработанный JSON в строке, которая начинается с string:. Я ожидаю, что resultItems будет одинаковым для обоих запросов, но это верно только в первом запросе. Обратите внимание, что он по-прежнему устанавливает resultCode и message в обеих попытках, поэтому он как минимум что-то делает.

Getting string and deserializing it
string: {"resultItems":[{"name":"MAX.PACKETSIZE","value":"64512"}],"message":"OK - the variables were successfully retrieved","resultCode":"0"}
Good constructor called
resultCode: 0
message: OK - the variables were successfully retrieved
resultItems: [{name=MAX.PACKETSIZE, value=64512}]

Getting object directly from the client
Blank constructor called
resultCode: 0
message: OK - the variables were successfully retrieved
resultItems: []

Кроме того, я бы предпочел избавиться от конструктора no-args, чтобы я мог заполнить все поля private final и инкапсулировать все правильно.

...