使用JacksonMapper反序列化Java 8 LocalDateTime

我已经阅读了几个问题,在这里有关于java.time.LocalDateTime和JSON属性之间的序列化和反序列化的答案,但我似乎无法让它工作。

我已经设法配置我的Spring Boot应用程序以我想要的格式返回日期( YYY-MM-dd HH:mm )但是我在JSON中以这种格式接受值时遇到问题。

这些是我到目前为止所做的所有事情:

jsr310添加了maven依赖:

  com.fasterxml.jackson.datatype jackson-datatype-jsr310  

我的主类中指定的jsr310

 @EntityScan(basePackageClasses = { App.class, Jsr310JpaConverters.class }) 

禁用序列化作为application.properties时间戳:

 spring.jackson.serialization.write_dates_as_timestamps=false 

这是我的日期时间实体映射:

 @Column(name = "start_date") @DateTimeFormat(iso = DateTimeFormat.ISO.TIME) @JsonFormat(pattern = "YYYY-MM-dd HH:mm") private LocalDateTime startDate; 

在我的数据库中,我将此日期存储为TIMESTAMP,格式如下: 2016-12-01T23:00:00+00:00

如果我通过我的控制器访问此实体,它将返回具有正确startDate格式的JSON。 当我尝试发布它并反序列化时,使用YYYY-MM-dd HH:mm格式,我得到以下exception:

 { "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.Parsed\n 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.Parsed\n at [Source: java.io.PushbackInputStream@679a734d; line: 6, column: 16] (through reference chain: com.gigsterous.api.model.Event[\"startDate\"])", "path": "/api/events" } 

我知道关于这个话题有很多答案,但是跟着他们并且尝试了几个小时并没有帮助我弄清楚我做错了什么,所以如果有人能指出我错过了什么,我会很高兴。 感谢您的任何意见!

编辑:这些是该过程中涉及的所有类:

库:

 @Repository public interface EventRepository extends PagingAndSortingRepository { } 

控制器:

 @RequestMapping(method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity 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; } 

您传递的日期时间不是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根本没有效果。 由于jackson正在进行去分离,并且它对弹簧注释没有任何了解,我也没有看到Spring在反序列化上下文中扫描这个注释。

或者,您可以在注册java时间模块时尝试设置格式化程序。

 LocalDateTimeDeserializer localDateTimeDeserializer = new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")); module.addDeserializer(LocalDateTime.class, localDateTimeDeserializer); 

以下是使用deseralizer的测试用例。 可能试图完全摆脱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

看到:

那是你在豆子里的财产

 @JsonProperty("start_date") @JsonFormat("YYYY-MM-dd HH:mm") @JsonSerialize(using = DateSerializer.class) private Date startDate; 

这样就实现了你的自定义类

 public class DateSerializer extends JsonSerializer implements ContextualSerializer { 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 createContextual(final SerializationConfig serializationConfig, final BeanProperty beanProperty) throws JsonMappingException { final AnnotatedElement annotated = beanProperty.getMember().getAnnotated(); return new DateSerializer(annotated.getAnnotation(JsonFormat.class).value()); } } 

在我们发布结果后试试这个。