使用 JacksonMapper 反序列化 Java 8 LocalDateTime [英] Deserialize Java 8 LocalDateTime with JacksonMapper
问题描述
我在 SO 中阅读了几个关于 java.time.LocalDateTime
和 JSON 属性之间的序列化和反序列化的问题和答案,但我似乎无法让它工作.
I have read several questions with answers here in SO concerning serialization and deserialization between java.time.LocalDateTime
and JSON property but I can't seem to get it working.
我已设法将 Spring Boot 应用程序配置为以我想要的格式返回日期 (YYY-MM-dd HH:mm
),但我在接受 JSON 格式的值时遇到问题.
I have managed to configure my Spring Boot Application to return the dates in the format I desire (YYY-MM-dd HH:mm
) but I have problems accepting values in this format in JSON.
这些是我迄今为止所做的所有事情:
These are all the things I have done so far:
为 jsr310
添加了 maven 依赖:
Added maven dependency for jsr310
:
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>
在我的主类中指定jsr310
:
@EntityScan(basePackageClasses = { App.class, Jsr310JpaConverters.class })
禁用序列化作为 application.properties
中的时间戳:
Disabled serialization as timestamps in application.properties
:
spring.jackson.serialization.write_dates_as_timestamps=false
这是我的日期时间实体映射:
And this is my entity mapping for datetime:
@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
.
In my database, I store this date as TIMESTAMP in the following format: 2016-12-01T23:00:00+00:00
.
如果我通过我的控制器访问这个实体,它会以正确的 startDate 格式返回 JSON.当我尝试发布它并反序列化它时,使用 YYYY-MM-dd HH:mm
格式,我得到以下异常:
If I access this entity via my controller, it returns the JSON with correct startDate format. When I try to post it and deserialize it though, using YYYY-MM-dd HH:mm
format, I get the following 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
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
at [Source: java.io.PushbackInputStream@679a734d; line: 6, column: 16] (through reference chain: com.gigsterous.api.model.Event["startDate"])",
"path": "/api/events"
}
我知道有很多关于这个话题的答案,但是关注他们并尝试了几个小时并没有帮助我弄清楚我做错了什么,所以如果有人能指出我遗漏了什么,我会很高兴.感谢您对此的任何意见!
I know that there are many answers concerning this topic but following them and trying for couple of hours did not help me to figure out what am I doing wrong so I would be glad if someone could point out to me what am I missing. Thanks for any input on this!
这些是过程中涉及的所有类:
These are all the classes involved in the process:
存储库:
@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:
My JSON request 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 本地日期时间格式.
The date time you're passing is not an ISO local date time format.
改为
@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"格式传递日期字符串.
and pass the date string in the format '2011-12-03T10:15:30'.
但如果您仍想传递自定义格式,则只需指定正确的格式化程序即可.
But if you still want to pass your custom format, you just have to specify the right formatter.
改为
@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 注释一无所知,而且我没有看到 spring 在反序列化上下文中扫描此注释.
I think your problem is the @DateTimeFormat has no effect at all. As the Jackson is doing the deserialization and it doesn't know anything about spring annotation, and I don't see spring scanning this annotation in the deserialization context.
或者,您可以在注册 Java 时间模块时尝试设置格式化程序.
Alternatively, you can try setting the formatter while registering the Java time module.
LocalDateTimeDeserializer localDateTimeDeserializer = new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"));
module.addDeserializer(LocalDateTime.class, localDateTimeDeserializer);
这是带有去盐器的测试用例,它工作正常.也许尝试完全摆脱那个 DateTimeFormat 注释.
Here is the test case with the deseralizer which works fine. Maybe try to get rid of that DateTimeFormat annotation altogether.
@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;
}
}
这篇关于使用 JacksonMapper 反序列化 Java 8 LocalDateTime的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!