web-dev-qa-db-fra.com

Erreur d'analyse JSON: impossible de construire une instance de Java.time.LocalDate: no Méthode constructeur/fabrique avec argument de chaîne à désérialiser à partir de la valeur String

Je suis nouveau dans le projet Spring Data REST et j'essaie de créer mon premier service RESTful. La tâche est simple, mais je suis coincé.

Je souhaite effectuer des opérations CRUD sur des données utilisateur stockées dans une base de données intégrée à l'aide de l'API RESTful. 

Mais je ne peux pas comprendre comment faire en sorte que le cadre Spring traite le birthData en tant que "1999-12-15" et le stocke en tant que Date locale. L'annotation @JsonFormat n'aide pas.

À l'heure actuelle, j'obtiens l'erreur:

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.jackson.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\"])"}

Comment le faire fonctionner, de sorte que le client appelle comme:

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

va effectivement stocker l'entité dans la base de données.

Vous trouverez ci-dessous des informations sur les cours.

La classe d'utilisateurs: 

package ru.zavanton.entities;


import com.fasterxml.jackson.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;
    }
}

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

}

Classe d'application:

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

    }
}
13
zavanton

Vous avez besoin de la dépendance de Jackson pour cette sérialisation et cette désérialisation.

Ajoutez cette dépendance:

Gradle:

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

Maven:

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

Après cela, vous devez dire à Jackson ObjectMapper d'utiliser JavaTimeModule . Pour cela, Autowire ObjectMapper dans la classe principale et y enregistrer JavaTimeModule.

import javax.annotation.PostConstruct;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.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());
  }
}

Après cela, Votre LocalDate et LocalDateTime doivent être sérialisés et désérialisés correctement.

13
SanketKD

En fin de compte, il ne faut pas oublier d’inclure la dépendance jacson dans le fichier pom. Cela a résolu le problème pour moi:

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

Si le problème est dû à l'API Instant Date, ajoutez les attributs Jackson suivants.

spring:
    application:
        name: data
    jackson:
serialization.write_dates_as_timestamps: false 

^ - ajoutez ceci dans votre fichier yml

jpa:
    open-in-view: false
0
Janki