Десериализовать Java 8 LocalDateTime с помощью JacksonMapper
я прочитал несколько вопросов с ответами в отношении сериализации и десериализации между java.time.LocalDateTime
и свойство JSON, но я не могу заставить его работать.
мне удалось настроить приложение Spring Boot для возврата дат в желаемом формате (YYY-MM-dd HH:mm
) но у меня проблемы с принятием значений в этом формате в JSON.
это все, что я сделал до сих пор:
добавлена зависимость maven для jsr310
:
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>
указано jsr310
в моем основном классе:
@EntityScan(basePackageClasses = { App.class, Jsr310JpaConverters.class })
отключена сериализация как метки времени в application.properties
:
spring.jackson.serialization.write_dates_as_timestamps=false
и это мое отображение сущности для datetime:
@Column(name = "start_date")
@DateTimeFormat(iso = DateTimeFormat.ISO.TIME)
@JsonFormat(pattern = "YYYY-MM-dd HH:mm")
private LocalDateTime startDate;
в моей базе данных я храню эту дату как метку времени в следующем формате:2016-12-01T23:00:00+00:00
.
если я обращаюсь к этому объекту через мой контроллер, он возвращает JSON с правильным форматом startDate. Когда я пытаюсь опубликовать его и десериализовать хотя, используя , я получаю следующее исключение:
{
"timestamp": "2016-10-30T14:22:25.285+0000",
"status": 400,
"error": "Bad Request",
"exception": "org.springframework.http.converter.HttpMessageNotReadableException",
"message": "Could not read document: Can not deserialize value of type java.time.LocalDateTime from String "2017-01-01 20:00": Text '2017-01-01 20:00' could not be parsed: Unable to obtain LocalDateTime from TemporalAccessor: {MonthOfYear=1, WeekBasedYear[WeekFields[SUNDAY,1]]=2017, DayOfMonth=1},ISO resolved to 20:00 of type java.time.format.Parsedn at [Source: java.io.PushbackInputStream@679a734d; line: 6, column: 16] (through reference chain: com.gigsterous.api.model.Event["startDate"]); nested exception is com.fasterxml.jackson.databind.exc.InvalidFormatException: Can not deserialize value of type java.time.LocalDateTime from String "2017-01-01 20:00": Text '2017-01-01 20:00' could not be parsed: Unable to obtain LocalDateTime from TemporalAccessor: {MonthOfYear=1, WeekBasedYear[WeekFields[SUNDAY,1]]=2017, DayOfMonth=1},ISO resolved to 20:00 of type java.time.format.Parsedn at [Source: java.io.PushbackInputStream@679a734d; line: 6, column: 16] (through reference chain: com.gigsterous.api.model.Event["startDate"])",
"path": "/api/events"
}
я знаю, что есть много ответов на эту тему, но следуя им и пытаясь в течение нескольких часов не помог мне понять, что я делаю неправильно, поэтому я был бы рад, если бы кто-то мог указать мне, что я упускаю. Спасибо за любой вклад в это!
EDIT: это все классы, участвующие в процесс:
репозитория:
@Repository
public interface EventRepository extends PagingAndSortingRepository<Event, Long> {
}
:
@RequestMapping(method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Event> createEvent(@RequestBody Event event) {
return new ResponseEntity<>(eventRepo.save(event), HttpStatus.CREATED);
}
мой запрос JSON payalod:
{
"name": "Test",
"startDate": "2017-01-01 20:00"
}
событие:
@Entity
@Table(name = "events")
@Getter
@Setter
public class Event {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "event_id")
private long id;
@Column(name = "name")
private String name;
@Column(name = "start_date")
@DateTimeFormat(iso = DateTimeFormat.ISO.TIME)
@JsonFormat(pattern = "YYYY-MM-dd HH:mm")
private LocalDateTime startDate;
}
3 ответов
дата, которую вы проходите, не является локальным форматом даты iso.
заменить на
@Column(name = "start_date")
@DateTimeFormat(iso = DateTimeFormatter.ISO_LOCAL_DATE_TIME)
@JsonFormat(pattern = "YYYY-MM-dd HH:mm")
private LocalDateTime startDate;
и передать строку с датой в формате '2011-12-03T10:15:30'.
но если вы все еще хотите передать свой пользовательский формат, используйте просто нужно указать правильный форматтер.
заменить на
@Column(name = "start_date")
@DateTimeFormat(iso = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"))
@JsonFormat(pattern = "YYYY-MM-dd HH:mm")
private LocalDateTime startDate;
Я думаю, что ваша проблема в том, что @DateTimeFormat не имеет никакого эффекта. Как Джексон делает deseralization и не знаю о весенней аннотации, и я не вижу весеннего сканирования этой аннотации в контексте десериализации.
кроме того, вы можете попробовать установить форматер при регистрации модуля времени java.
LocalDateTimeDeserializer localDateTimeDeserializer = new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"));
module.addDeserializer(LocalDateTime.class, localDateTimeDeserializer);
вот тестовый случай с десерализатором, который отлично работает. Может быть, попытаться избавиться от этой аннотации DateTimeFormat вообще.
@RunWith(JUnit4.class)
public class JacksonLocalDateTimeTest {
private ObjectMapper objectMapper;
@Before
public void init() {
JavaTimeModule module = new JavaTimeModule();
LocalDateTimeDeserializer localDateTimeDeserializer = new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"));
module.addDeserializer(LocalDateTime.class, localDateTimeDeserializer);
objectMapper = Jackson2ObjectMapperBuilder.json()
.modules(module)
.featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
.build();
}
@Test
public void test() throws IOException {
final String json = "{ \"date\": \"2016-11-08 12:00\" }";
final JsonType instance = objectMapper.readValue(json, JsonType.class);
assertEquals(LocalDateTime.parse("2016-11-08 12:00",DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm") ), instance.getDate());
}
}
class JsonType {
private LocalDateTime date;
public LocalDateTime getDate() {
return date;
}
public void setDate(LocalDateTime date) {
this.date = date;
}
}
вы использовали неправильный случай письма в течение года в строке:
@JsonFormat(pattern = "YYYY-MM-dd HH:mm")
должно быть:
@JsonFormat(pattern = "yyyy-MM-dd HH:mm")
С этим изменением все работает так, как ожидалось.
Вы можете реализовать свой JsonSerializer
посмотреть:
что ваша собственность в bean
@JsonProperty("start_date")
@JsonFormat("YYYY-MM-dd HH:mm")
@JsonSerialize(using = DateSerializer.class)
private Date startDate;
таким образом реализуйте свой пользовательский класс
public class DateSerializer extends JsonSerializer<Date> implements ContextualSerializer<Date> {
private final String format;
private DateSerializer(final String format) {
this.format = format;
}
public DateSerializer() {
this.format = null;
}
@Override
public void serialize(final Date value, final JsonGenerator jgen, final SerializerProvider provider) throws IOException {
jgen.writeString(new SimpleDateFormat(format).format(value));
}
@Override
public JsonSerializer<Date> createContextual(final SerializationConfig serializationConfig, final BeanProperty beanProperty) throws JsonMappingException {
final AnnotatedElement annotated = beanProperty.getMember().getAnnotated();
return new DateSerializer(annotated.getAnnotation(JsonFormat.class).value());
}
}
попробуйте это после результата post для нас.