web-dev-qa-db-ja.com

JSON解析エラー:Java.time.LocalDateのインスタンスを構築できません:ストリング値からデシリアライズするストリング引数コンストラクター/ファクトリーメソッドがありません

Spring Data RESTプロジェクトは初めてで、最初のRESTfulサービスを作成しようとしています。タスクは簡単ですが、行き詰まっています。

RESTful APIを使用して、埋め込みデータベースに保存されているユーザーデータに対してCRUD操作を実行したい。

しかし、SpringフレームワークがbirthDataを「1999-12-15」として処理し、LocalDateとして保存する方法を理解することはできません。 @JsonFormatアノテーションは役に立ちません。

現在、私はエラーを受け取ります:

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

クライアントが次のように呼び出すように機能させる方法:

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

実際にエンティティをデータベースに保存します。

以下は、クラスに関する情報です。

ユーザークラス:

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

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

}

アプリケーションクラス:

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

    }
}
25
zavanton

このシリアライゼーションとデシリアライゼーションには、ジャクソンの依存関係が必要です。

この依存関係を追加します。

Gradle:

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

メイヴン:

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

その後、JavaTimeModuleを使用するようにJackson ObjectMapperに指示する必要があります。それを行うには、メインクラスでObjectMapperをAutowireし、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());
  }
}

その後、LocalDateとLocalDateTimeを正しくシリアル化および逆シリアル化する必要があります。

28
SanketKD

判明したように、jacson依存関係をpomファイルに含めることを忘れないでください。これで問題が解決しました:

<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>
13
zavanton

Instant date APIが原因で問題が発生している場合は、次のjackson属性を追加します。

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

^-これをymlファイルに追加します

jpa:
    open-in-view: false
1
Janki

さて、私がすべてのプロジェクトで行うことは、上記のオプションの組み合わせです。

まず、jsr310依存関係を追加します。

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

重要な詳細:この依存関係を置きます最上部依存関係リストの。このpom.xmlへの依存関係がある場合でも、Localdateエラーが続くプロジェクトを既に見ています。しかし、依存関係の順序を変更すると、エラーはなくなりました。

/src/main/resources/application.ymlファイルで、write-dates-as-timestampsプロパティを設定します。

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

そして、次のようにObjectMapper Beanを作成します。

@Configuration
public class WebConfigurer {

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

}

この構成に従って、変換はエラーなしで常にSpring Boot 1.5.xで機能します。

ボーナス:Spring AMQPキューの構成

Spring AMQPを使用して、Jackson2JsonMessageConverterの新しいインスタンスがある場合は注意してください(SimpleRabbitListenerContainerFactoryを作成するときの一般的なこと)。次のように、ObjectMapper Beanを渡す必要があります。

Jackson2JsonMessageConverter converter = new Jackson2JsonMessageConverter(objectMapper);

それ以外の場合は、同じエラーが表示されます。

0
Dherik