Я начинаю писать клиент для 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
и инкапсулировать все правильно.