使用 JacksonMapper 反序列化 Java 8 LocalDateTime

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/40327970/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 22:36:50  来源:igfitidea点击:

Deserialize Java 8 LocalDateTime with HymansonMapper

javajsonjpaspring-bootHymanson

提问by Smajl

I have read several questions with answers here in SO concerning serialization and deserialization between java.time.LocalDateTimeand JSON property but I can't seem to get it working.

我在 SO 中阅读了几个关于java.time.LocalDateTimeJSON 属性之间的序列化和反序列化的问题和答案,但我似乎无法让它工作。

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.

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

These are all the things I have done so far:

这些是我迄今为止所做的所有事情:

Added maven dependency for jsr310:

添加了 Maven 依赖项jsr310

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

Specified jsr310in my main class:

jsr310在我的主类中指定:

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

Disabled serialization as timestamps in application.properties:

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

spring.Hymanson.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.

在我的数据库,我存储这个日期作为TIMESTAMP的格式如下: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:mmformat, I get the following exception:

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

{
  "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.Hymanson.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:

我的JSON请求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;
}

采纳答案by Sagar Veeram

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

您传递的日期时间不是 iso 本地日期时间格式。

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'.

并以“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 Hymanson is doing the deseralization and it doesnt know anything about spring annotation and I dont see spring scanning this annotation in the deserialization context.

我认为你的问题是 @DateTimeFormat 根本没有效果。由于 Hymanson 正在进行反序列化,它对 spring 注释一无所知,我没有看到 spring 在反序列化上下文中扫描此注释。

Alternatively, you can try setting the formatter while registering the java time module.

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

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.

这是带有去盐器的测试用例,它工作正常。可能会尝试完全摆脱那个 DateTimeFormat 注释。

@RunWith(JUnit4.class)
public class HymansonLocalDateTimeTest {

    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 = Hymanson2ObjectMapperBuilder.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;
    }
}

回答by Maciej Walkowiak

You used wrong letter case for year in line:

您在年份中使用了错误的字母大小写:

@JsonFormat(pattern = "YYYY-MM-dd HH:mm")

Should be:

应该:

@JsonFormat(pattern = "yyyy-MM-dd HH:mm")

With this change everything is working as expected.

通过此更改,一切都按预期工作。

回答by Marcelo Ferreira

You can implement your JsonSerializer

你可以实现你的 JsonSerializer

See:

看:

That your propertie in bean

你在 bean 中的属性

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

That way implement your custom class

这样实现你的自定义类

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

}

Try this after post result for us.

在为我们发布结果后尝试此操作。

回答by LeandroPL

UPDATE:

更新:

Change to:

改成:

@Column(name = "start_date")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm", iso = ISO.DATE_TIME)
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm")
private LocalDateTime startDate;

JSON request:

JSON 请求:

{
 "startDate":"2019-04-02 11:45"
}

回答by Alferd Nobel

This worked for me :

这对我有用:

import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.format.annotation.DateTimeFormat.ISO;

@Column(name="end_date", nullable = false)
@DateTimeFormat(iso = ISO.DATE_TIME)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm")
private LocalDateTime endDate;

回答by user5515

This worked for me:

这对我有用:

 @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSZ", shape = JsonFormat.Shape.STRING)
 private LocalDateTime startDate;