JSON 解析错误:无法构造 java.time.LocalDate 的实例:没有从字符串值反序列化的字符串参数构造函数/工厂方法

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/45863678/
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-09-03 18:59:00  来源:igfitidea点击:

JSON parse error: Can not construct instance of java.time.LocalDate: no String-argument constructor/factory method to deserialize from String value

jsonrestspring-bootHymansonspring-data-rest

提问by zavanton

I am new to Spring Data REST project and I am trying to create my first RESTful service. The task is simple, but I am stuck.

我是 Spring Data REST 项目的新手,我正在尝试创建我的第一个 RESTful 服务。任务很简单,但我被卡住了。

I want to perform CRUD operations on a user data stored in an embedded database using RESTful API.

我想使用 RESTful API 对存储在嵌入式数据库中的用户数据执行 CRUD 操作。

But I cannot figure out how to make the Spring framework process the birthData as "1999-12-15" and store it as a LocalDate. The @JsonFormat annotation does not help.

但我无法弄清楚如何让 Spring 框架将birthData 处理为“1999-12-15”并将其存储为 LocalDate。@JsonFormat 注释没有帮助。

At present I get the error:

目前我收到错误:

HTTP/1.1 400 
Content-Type: application/hal+json;charset=UTF-8
Transfer-Encoding: chunked
Date: Thu, 24 Aug 2017 13:36:51 GMT
Connection: close

{"cause":{"cause":null,"message":"Can not construct instance of java.time.LocalDate: 
no String-argument constructor/factory method to deserialize from String value ('1999-10-10')\n 
at [Source: org.apache.catalina.connector.CoyoteInputStream@4ee2a60e; 
line: 1, column: 65] (through reference chain: ru.zavanton.entities.User[\"birthDate\"])"},
"message":"JSON parse error: Can not construct instance of java.time.LocalDate: 
no String-argument constructor/factory method to deserialize from String value ('1999-10-10'); nested exception is com.fasterxml.Hymanson.databind.JsonMappingException: 
Can not construct instance of java.time.LocalDate: no String-argument constructor/factory method to deserialize from String value ('1999-10-10')\n 
at [Source: org.apache.catalina.connector.CoyoteInputStream@4ee2a60e; line: 1, column: 65] (through reference chain: ru.zavanton.entities.User[\"birthDate\"])"}

How to make it work, so that client calls like:

如何使其工作,以便客户端调用:

curl -i -X POST -H "Content-Type:application/json" -d "{  \"firstName\" : \"John\",  \"lastName\" : \"Johnson\", \"birthDate\" : \"1999-10-10\", \"email\" : \"[email protected]\" }" http://localhost:8080/users

will actually store the entity into the database.

实际上会将实体存储到数据库中。

Below is the information about the classes.

以下是有关课程的信息。

The user class:

用户类:

package ru.zavanton.entities;


import com.fasterxml.Hymanson.annotation.JsonFormat;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import java.time.LocalDate;

@Entity
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;

    private String firstName;
    private String lastName;

    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
    private LocalDate birthDate;

    private String email;
    private String password;

    public long getId() {
        return id;
    }

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

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public LocalDate getBirthDate() {
        return birthDate;
    }

    public void setBirthDate(LocalDate birthDate) {
        this.birthDate = birthDate;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

The UserRepository class:

UserRepository 类:

package ru.zavanton.repositories;

import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
import ru.zavanton.entities.User;

@RepositoryRestResource(collectionResourceRel = "users", path = "users")
public interface UserRepository extends PagingAndSortingRepository<User, Long> {

    User findByEmail(@Param("email") String email);

}

Application class:

应用类:

package ru.zavanton;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {

    public static void main(String[] args) {

        SpringApplication.run(Application.class, args);

    }
}

回答by SanketKD

You need Hymanson dependency for this serialization and deserialization.

此序列化和反序列化需要 Hymanson 依赖项。

Add this dependency:

添加此依赖项:

Gradle:

摇篮:

compile("com.fasterxml.Hymanson.datatype:Hymanson-datatype-jsr310:2.9.4")

Maven:

马文:

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

After that, You need to tell Hymanson ObjectMapper to use JavaTimeModule. To do that, Autowire ObjectMapper in the main class and register JavaTimeModule to it.

之后,您需要告诉 Hymanson ObjectMapper 使用 JavaTimeModule。为此,在主类中 Autowire ObjectMapper 并将 JavaTimeModule 注册到它。

import javax.annotation.PostConstruct;
import com.fasterxml.Hymanson.databind.ObjectMapper;
import com.fasterxml.Hymanson.datatype.jsr310.JavaTimeModule;

@SpringBootApplication
public class MockEmployeeApplication {

  @Autowired
  private ObjectMapper objectMapper;

  public static void main(String[] args) {
    SpringApplication.run(MockEmployeeApplication.class, args);

  }

  @PostConstruct
  public void setUp() {
    objectMapper.registerModule(new JavaTimeModule());
  }
}

After that, Your LocalDate and LocalDateTime should be serialized and deserialized correctly.

之后,您的 LocalDate 和 LocalDateTime 应该正确序列化和反序列化。

回答by zavanton

As it turns out, one should not forget to include jacson dependency into the pom file. This solved the issue for me:

事实证明,不应忘记在 pom 文件中包含 jacson 依赖项。这为我解决了这个问题:

<dependency>
    <groupId>com.fasterxml.Hymanson.module</groupId>
    <artifactId>Hymanson-module-parameter-names</artifactId>
</dependency>
<dependency>
    <groupId>com.fasterxml.Hymanson.datatype</groupId>
    <artifactId>Hymanson-datatype-jdk8</artifactId>
</dependency>
<dependency>
    <groupId>com.fasterxml.Hymanson.datatype</groupId>
    <artifactId>Hymanson-datatype-jsr310</artifactId>
</dependency>

回答by Mateen

I had a similar issue which i solved by making two changes

我有一个类似的问题,我通过进行两次更改来解决

  1. added below entry in application.yaml file

    spring: Hymanson: serialization.write_dates_as_timestamps: false

  2. add below two annotations in pojo

    1. @JsonDeserialize(using = LocalDateDeserializer.class)
    2. @JsonSerialize(using = LocalDateSerializer.class)

    sample example

    import com.fasterxml.Hymanson.databind.annotation.JsonDeserialize; import com.fasterxml.Hymanson.databind.annotation.JsonSerialize; public class Customer { //your fields ... @JsonDeserialize(using = LocalDateDeserializer.class) @JsonSerialize(using = LocalDateSerializer.class) protected LocalDate birthdate; }

  1. 在 application.yaml 文件中添加以下条目

    spring: Hymanson: serialization.write_dates_as_timestamps: false

  2. 在 pojo 中添加以下两个注释

    1. @JsonDeserialize(使用 = LocalDateDeserializer.class)
    2. @JsonSerialize(使用 = LocalDateSerializer.class)

    示例

    import com.fasterxml.Hymanson.databind.annotation.JsonDeserialize; import com.fasterxml.Hymanson.databind.annotation.JsonSerialize; public class Customer { //your fields ... @JsonDeserialize(using = LocalDateDeserializer.class) @JsonSerialize(using = LocalDateSerializer.class) protected LocalDate birthdate; }

then the following json requests worked for me

然后以下 json 请求对我有用

  1. sample request format as string
  1. 示例请求格式为字符串

{ "birthdate": "2019-11-28" }

{ "birthdate": "2019-11-28" }

  1. sample request format as array
  1. 示例请求格式为数组

{ "birthdate":[2019,11,18] }

{ "birthdate":[2019,11,18] }

Hope it helps!!

希望能帮助到你!!

回答by sparkyspider

Spring Boot 2.2.2 / Gradle:

Spring Boot 2.2.2 / Gradle:

Gradle (build.gradle):

摇篮(build.gradle):

implementation("com.fasterxml.Hymanson.datatype:Hymanson-datatype-jsr310")

Entity (User.class):

实体(User.class):

LocalDate dateOfBirth;

Code:

代码:

ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
User user = mapper.readValue(json, User.class);

回答by Dherik

Well, what I do on every project is a mix of the options above.

好吧,我在每个项目上所做的都是上述选项的混合。

First, add the jsr310 dependency:

首先,添加jsr310依赖:

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

Important detail: put this dependency on the topof your depedencies list. I already see a project where the Localdate error persists even with this dependency on the pom.xml. But changing the order of the depedency the error was gone.

重要细节:将此依赖项放在依赖项列表的顶部。我已经看到一个项目,即使对 pom.xml 有这种依赖性,Localdate 错误仍然存​​在。但是改变依赖的顺序错误消失了。

On your /src/main/resources/application.ymlfile, setup the write-dates-as-timestampsproperty:

在您的/src/main/resources/application.yml文件上,设置write-dates-as-timestamps属性:

spring:
  Hymanson:
    serialization:
      write-dates-as-timestamps: false

And create a ObjectMapperbean as this:

并创建一个ObjectMapperbean,如下所示:

@Configuration
public class WebConfigurer {

    @Bean
    @Primary
    public ObjectMapper objectMapper(Hymanson2ObjectMapperBuilder builder) {
        ObjectMapper objectMapper = builder.build();
        objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
        return objectMapper;
    }

}

Following this configuration, the conversion always work on Spring Boot 1.5.x without any error.

按照此配置,转换始终在 Spring Boot 1.5.x 上正常工作,不会出现任何错误。

Bonus: Spring AMQP Queue configuration

奖励:Spring AMQP 队列配置

Working with Spring AMQP, pay attention if you have a new instance of Hymanson2JsonMessageConverter(common thing when creating a SimpleRabbitListenerContainerFactory). You need to pass the ObjectMapperbean to it, like:

使用 Spring AMQP,请注意您是否有一个新实例Hymanson2JsonMessageConverter(创建 时常见的事情SimpleRabbitListenerContainerFactory)。您需要将ObjectMapperbean传递给它,例如:

Hymanson2JsonMessageConverter converter = new Hymanson2JsonMessageConverter(objectMapper);

Otherwise, you will receive the same error.

否则,您将收到相同的错误。