没有要从字符串值反序列化的字符串参数构造函数/工厂方法('2018-12-14')

时间:2018-12-14 00:04:01

标签: spring-boot jackson spring-rest localdate

这个问题与this几乎相同,但是不同之处在于我试图将String转换为LocalDate。这是来自STS的错误:

  

2018-12-14 00:47:04.507 WARN 6216 --- [nio-8080-exec-2]   .w.s.m.s.DefaultHandlerExceptionResolver:已解决   [org.springframework.http.converter.HttpMessageNotReadableException:   JSON解析错误:无法构造java.time.LocalDate的实例:   没有要从中反序列化的String-argument构造函数/工厂方法   字符串值('2018-12-14');嵌套异常为   com.fasterxml.jackson.databind.JsonMappingException:无法构造   java.time.LocalDate的实例:无字符串参数   从字符串值反序列化的构造函数/工厂方法   ('2018-12-14'),网址为[Source:java.io.PushbackInputStream@73ff9989;   行:3,列:16](通过参考链:   com.xxxxx.xxxxxx.model.request.ReservationRequest [“ checkin”])]

这里是邮递员:

  

{       “时间戳记”:1544744824516,       “状态”:400,       “错误”:“错误请求”,       “ exception”:“ org.springframework.http.converter.HttpMessageNotReadableException”,       “ message”:“ JSON解析错误:无法构造java.time.LocalDate的实例:否字符串参数构造函数/工厂方法   从字符串值反序列化('2018-12-14');嵌套异常为   com.fasterxml.jackson.databind.JsonMappingException:无法构造   java.time.LocalDate的实例:无字符串参数   从字符串值反序列化的构造函数/工厂方法   ('2018-12-14')\ n,位于[来源:java.io.PushbackInputStream@73ff9989;   行:3,列:16](通过参考链:   com.xxxxx.xxxxx.model.request.ReservationRequest [\“ checkin \”])“,       “ path”:“ / room / reservation / v1”}

POST请求为:

{
    "id": 12345,
    "checkin": "2018-12-14",
    "checkout": "2018-12-17"
}

相关类别为

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;

@Configuration
public class ApiConfig {

    @Bean
    public ObjectMapper objectMapper() {
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.registerModule(new JavaTimeModule());
        return new ObjectMapper();
    }

    @Bean
    public ObjectWriter objectWriter(ObjectMapper objectMapper) {
        return objectMapper.writerWithDefaultPrettyPrinter();
    }
}

import java.time.LocalDate;
import org.springframework.format.annotation.DateTimeFormat;

public class ReservationRequest {

    private Long id;
    @DateTimeFormat(iso = DateTimeFormat.ISO.DATE)
    private LocalDate checkin;
    @DateTimeFormat(iso = DateTimeFormat.ISO.DATE)
    private LocalDate checkout;

    public ReservationRequest() {
        super();
    }

    public ReservationRequest(Long id, LocalDate checkin, LocalDate checkout) {
        super();
        this.id = id;
        this.checkin = checkin;
        this.checkout = checkout;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public LocalDate getCheckin() {
        return checkin;
    }

    public void setCheckin(LocalDate checkin) {
        this.checkin = checkin;
    }

    public LocalDate getCheckout() {
        return checkout;
    }

    public void setCheckout(LocalDate checkout) {
        this.checkout = checkout;
    }
}

import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.xxxxx.xxxxxx.model.request.ReservationRequest;
import com.xxxxx.xxxxxx.model.response.ReservationResponse;

@RestController
@RequestMapping(ResourceConstants.ROOM_RESERVATION_V1)
public class ReservationResource {

    @RequestMapping(path = "", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public ResponseEntity<ReservationResponse> getAvaiableRooms(
            @RequestParam(value = "checkin") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate checkin,
            @RequestParam(value = "checkout") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate checkout) {
        return new ResponseEntity<>(new ReservationResponse(), HttpStatus.OK);
    }

    @RequestMapping(path = "", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE, consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public ResponseEntity<ReservationResponse> createReservation(@RequestBody ReservationRequest reservationRequest) {

        return new ResponseEntity<>(new ReservationResponse(), HttpStatus.CREATED);
    }

    @RequestMapping(path = "", method = RequestMethod.PUT, produces = MediaType.APPLICATION_JSON_UTF8_VALUE, consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public ResponseEntity<ReservationResponse> updateReservation(@RequestBody ReservationRequest reservationRequest) {

        return new ResponseEntity<>(new ReservationResponse(), HttpStatus.OK);
    }

    @RequestMapping(path = "/{reservationId}", method = RequestMethod.DELETE)
    public ResponseEntity<Void> deleteReservation(@PathVariable long reservationId) {

        return new ResponseEntity<>(HttpStatus.NO_CONTENT);
    }
}

为了防万一,我包括了进口。

无论如何,如果我将ReservationRequest更改为具有Strings而不是LocalDate的字段,则不会产生错误

public class ReservationRequest {

    private Long id;
    @DateTimeFormat(iso = DateTimeFormat.ISO.DATE)
    private String checkin;
    @DateTimeFormat(iso = DateTimeFormat.ISO.DATE)
    private String checkout;

    public ReservationRequest() {
        super();
    }

    public ReservationRequest(Long id, String checkin, String checkout) {
        super();
        this.id = id;
        this.checkin = checkin;
        this.checkout = checkout;
    }

(getters and setters updated as well)

JDK 1.8; springBootVersion ='1.5.17.RELEASE';名称:“ jackson-datatype-jsr310”,版本:“ 2.9.7”

问题是为什么它不能与 LocalDate 一起使用?

更新:尝试了these解决方案,并添加了@JsonSerialize和@JsonDeserialize,因为两者都不objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);         或objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);

工作正常,现在看起来像:

public class ReservationRequest {

    private Long id;
    @JsonSerialize(using = ToStringSerializer.class)
    @JsonDeserialize(using = LocalDateDeserializer.class)
    //@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
    @DateTimeFormat(iso = DateTimeFormat.ISO.DATE)
    private LocalDate checkin;
    @JsonSerialize(using = ToStringSerializer.class)
    @JsonDeserialize(using = LocalDateDeserializer.class)
    //@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
    @DateTimeFormat(iso = DateTimeFormat.ISO.DATE)
    private LocalDate checkout;

    public ReservationRequest() {
        super();
    }

因此,现在看来它可以工作,但是我不知道这是否是一个好的解决方案?

3 个答案:

答案 0 :(得分:1)

我最近遇到了同样的问题,错误的原因是我的json字符串周围有双引号,当我删除它时,它工作得很好

答案 1 :(得分:0)

我认为现在回答同一问题的帖子为时已晚,以下注释很有帮助。

@JsonFormat(pattern = "yyyy-MM-dd")
private LocalDate dateOfBirth;

:)

答案 2 :(得分:0)

我认为问题出在这里

@Bean
public ObjectMapper objectMapper() {
    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.registerModule(new JavaTimeModule());
    return new ObjectMapper();
}

您必须返回配置的objectMapper而不是新实例:

@Bean
public ObjectMapper objectMapper() {
    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)
    objectMapper.registerModule(new JavaTimeModule()
            .addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern("M/d/yyyy")))
            .addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern("M/d/yyyy"))))
    return objectMapper;
}