使用JacksonMapper反序列化Java 8 LocalDateTime [英] Deserialize Java 8 LocalDateTime with JacksonMapper

查看:4183
本文介绍了使用JacksonMapper反序列化Java 8 LocalDateTime的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经在SO中阅读了几个问题,关于 java.time.LocalDateTime 和JSON属性之间的序列化和反序列化,但我似乎无法使其正常工作。



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



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



jsr310 添加了maven依赖项:

 <依赖性> 
< 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 

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

  @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



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

  {
timestamp:2016-10-30T14:22:25.285 + 0000,
status:400,
错误:错误请求,
异常:org.springframework.http.converter.HttpMessageNotReadableException,
消息:无法读取文档:无法反序列化值从字符串\2017-01-01 20:00\输入java.time.LocalDateTime:无法解析文本'2017-01-01 20:00':无法从TemporalAccessor获取LocalDateTime:{MonthOfYear = 1 ,WeekBasedYear [WeekFields [SUNDAY,1]] = 2017,DayOfMonth = 1},ISO解析为类型java.time.format.Parsed \ n的20:00在[来源:java.io.PushbackInputStream@679a734d;行: 6,柱:](通过参考链:com.gigsterous.api.model.Event [\ startDate\])16;嵌套的异常是com.fasterxml.jackson.databind.exc.InvalidFormatException:不能反序列化值类型ja来自String \2017-01-01 20:00\的va.time.LocalDateTime:无法解析文本'2017-01-01 20:00':无法从TemporalAccessor获取LocalDateTime:{MonthOfYear = 1, WeekBasedYear [WeekFields [SUNDAY,1]] = 2017,DayOfMonth = 1},ISO解析为类型java.time.format.Parsed \ n的20:00在[来源:java.io.PushbackInputStream@679a734d; line:6,column:16](通过引用链:com.gigsterous.api.model.Event [\startDate \]),
path:/ api / events
}

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



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



存储库:

  @Repository 
公共接口EventRepository扩展PagingAndSortingRepository<事件,长> {
}



'p>控制器:

  @RequestMapping(方法= RequestMethod.POST,消耗= MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity< Event> createEvent(@RequestBody Event event){
返回新的ResponseEntity<>(eventRepo.save(event),HttpSt atus.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(名称= 起始日期)
@DateTimeFormat(异= DateTimeFormat.ISO.TIME)
@JsonFormat(图案=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(名称= 起始日期)
@DateTimeFormat(异= DateTimeFormatter.ofPattern(YYYY-MM -dd HH:mm))
@JsonFormat(pattern =YYYY-MM-dd HH:mm)
private LocalDateTime startDate;

我认为你的问题是@DateTimeFormat根本没有效果。由于杰克逊正在进行解除分类,并且它对弹簧注释没有任何了解,因此我没有看到Spring在反序列化上下文中扫描此注释。



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

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

这是deseralizer的测试用例,工作正常。可能是试图摆脱DateTimeFormat标注完全的。

  @RunWith(JUnit4.class)
公共类JacksonLocalDateTimeTest {

私有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(模块)
.featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
.build();
}

@Test
public void test()抛出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());
}
}


类JsonType {
private LocalDateTime date;

public LocalDateTime getDate(){
return date;
}

public void setDate(LocalDateTime date){
this.date = date;
}
}


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.

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:

Added maven dependency for jsr310:

<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jsr310</artifactId>
</dependency>

Specified jsr310 in my main class:

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

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;

In my database, I store this date as TIMESTAMP in the following format: 2016-12-01T23:00:00+00:00.

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\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"
}

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!

EDIT: These are all the classes involved in the process:

Repository:

@Repository
public interface EventRepository extends PagingAndSortingRepository<Event, Long> {
}

Controller:

@RequestMapping(method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Event> createEvent(@RequestBody Event event) {
        return new ResponseEntity<>(eventRepo.save(event), HttpStatus.CREATED);
}

My JSON request payalod:

{
  "name": "Test",
  "startDate": "2017-01-01 20:00"
}

Event:

@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;
}

解决方案

The date time you're passing is not a iso local date time format.

Change to

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

and pass date string in the format '2011-12-03T10:15:30'.

But if you still want to pass your custom format, use just have to specify the right formatter.

Change to

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

I think your problem is the @DateTimeFormat has no effect at all. As the jackson is doing the deseralization and it doesnt know anything about spring annotation and I dont see spring scanning this annotation in the deserialization context.

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);

Here is the test case with the deseralizer which works fine. May be 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆