JAX-RS и java.time.LocalDate в качестве входного параметра
Проблема с использованием JAX-RS и java.time.LocalDate
(Java8).
Я хочу передать такой объект в метод JAX-RS, используя JSON:
Person {
java.time.LocalDate birthDay;
}
Исключение, которое я получаю:
com.fasterxml.jackson.databind.JsonMappingException
: Не найдено подходящего конструктора для типа [простой тип, классjava.time.LocalDate
]: невозможно создать экземпляр объекта JSON (нужно добавить / включить информацию о типе?) в [Source:io.undertow.servlet.spec.ServletInputStreamImpl@21cca2c1
; строка: 2, столбец: 3]
Как я могу создать какой-то перехватчик, который отображает JSON-даты java.time.LocalDate
? Я пытался реализовать MessageBodyReader
, но если LocalDate
это поле в другом классе, я должен написать MessageBodyReader
для каждого класса проведения LocalDate
(насколько я понял).
(Java EE7 (используется только javaee-api и не требуется никаких сторонних зависимостей), JAX-RS, Java 8, Wildfly 8.2)
Какие-либо предложения?
1 ответ
Обычно я бы сказал написать сериализатор / десериализатор для Джексона, но, поскольку вам не нужны никакие другие зависимости, вы можете использовать решения JAXB. Джексон (с Resteasy) поставляется с поддержкой аннотаций JAXB. Итак, что мы можем сделать, это просто написать XmlAdapter
преобразовать из строки в LocalDate
, Примером будет что-то вроде
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class LocalDateAdapter extends XmlAdapter<String, LocalDate> {
@Override
public LocalDate unmarshal(String dateString) throws Exception {
return LocalDate.parse(dateString, DateTimeFormatter.ISO_DATE);
}
@Override
public String marshal(LocalDate localDate) throws Exception {
return DateTimeFormatter.ISO_DATE.format(localDate);
}
}
Вы можете выбрать любое форматирование, которое вы хотите, я просто использовал DateTimeFormatter.ISO_DATE
, который в основном будет искать этот формат (2011-12-03).
Затем все, что вам нужно сделать, это аннотировать поле для получателя типа
public class Person {
private LocalDate birthDate;
@XmlJavaTypeAdapter(LocalDateAdapter.class)
public LocalDate getBirthDate() { return birthDate; }
public void setBirthDate(LocalDate birthDate) {
this.birthDate = birthDate;
}
}
Если вы не хотите загромождать классы своей модели этой аннотацией, вы можете просто объявить аннотацию на уровне пакета.
В package-info.java
файл в том же пакете, что и класс модели, добавьте
@XmlJavaTypeAdapters({
@XmlJavaTypeAdapter(type = LocalDate.class,
value = LocalDateAdapter.class)
})
package thepackage.of.the.models;
import java.time.LocalDate;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapters;
Тестовое задание
@Path("/date")
public class DateResource {
@POST
@Consumes(MediaType.APPLICATION_JSON)
public Response postPerson(Person person) {
return Response.ok(DateTimeFormatter.ISO_DATE.format(
person.getBirthDate())).build();
}
}
@Test
public void testResteasy() throws Exception {
WebTarget target = client.target(
TestPortProvider.generateURL(BASE_URI)).path("date");
String person = "{\"birthDate\":\"2015-01-04\"}";
Response response = target.request().post(Entity.json(person));
System.out.println(response.readEntity(String.class));
response.close();
}
Результат: 2015-01-04
ОБНОВИТЬ
Также для Джексона (я знаю, что ОП говорит без зависимостей, но это для других), вы можете использовать модуль https://github.com/FasterXML/jackson-datatype-jsr310. Смотрите полное решение здесь