web-dev-qa-db-ja.com

Spring Bootは、JacksonでJava.time.LocalDateTimeをシリアル化してISO-8601 JSONタイムスタンプを返す問題ですか?

私はスプリングブートでいくつかのモデルを変換することに取り組んでいますREST APIアプリを使用するJava 8のJava.time.LocalDateTimeの代わりにjodaのDateTime。API呼び出しから返されるタイムスタンプがISO_8601形式に準拠するようにします。動機は、Java 8の時間( 詳細はこちら )。

難しいことは、LocalDateTimeを含むオブジェクトをJSONにシリアル化することです。

たとえば、次のエンティティがあります。

// ... misc imports

import Java.time.LocalDateTime;
import Java.time.ZoneOffset;

@Data 
@Entity
@Table(name = "users")
public class User {

    @Id @Column
    private String id;

    @Column
    private String name;

    @Column
    private String email;

    @Column
    @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss", timezone = "UTC")
    private Java.time.LocalDateTime createdAt;

    public User(String name, String email) {
        this.id = Utils.generateUUID();
        this.createdAt = LocalDateTime.now(ZoneOffset.UTC);
    }
}

タイムスタンプジャクソン機能として日付をオフにするようにapplication.propertiesを設定しました:

spring.jackson.serialization.WRITE_DATES_AS_TIMESTAMPS = false

私のMavenデプス:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <version>1.3.6.RELEASE</version>
</dependency>

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

<dependency>
     <groupId>org.hibernate</groupId>
     <artifactId>hibernate-core</artifactId>
     <version>5.0.1.Final</version>
 </dependency>

最後に、コントローラーを介してJSON表現を取得しようとします。

@RequestMapping("/users")
@RestController
public class UserController {

    private UserService userService;

    @Autowired
    public UserController(UserService userService) {
        this.userService = userService;
    }

    @RequestMapping(
        value = "/{id}",
        method = RequestMethod.GET,
        produces = MediaType.APPLICATION_JSON_UTF8_VALUE
    )
    public User getUser(@PathVariable("id") String id) {
        return userService.findById(id);
    }
}

このエンドポイントを実際に呼び出すと、次の例外が発生します。

Java.lang.NoSuchMethodError: 
com.fasterxml.jackson.datatype.jsr310.ser.JSR310FormattedSerializerBase.findFormatOverrides(Lcom/fasterxml/jackson/databind/SerializerProvider;Lcom/fasterxml/jackson/databind/BeanProperty;Ljava/lang/Class;)Lcom/fasterxml/jackson/annotation/JsonFormat$Value;

または、構成クラスでアプリのObjectMapperも構成しました。

@Configuration
public class ServiceConfiguration {

    @Bean
    public ObjectMapper getJacksonObjectMapper() {
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.registerModule(new JavaTimeModule());
        objectMapper.configure(
            com.fasterxml.jackson.databind.SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,
            false
        );
        return objectMapper;
    }
}

どんなリードも大歓迎です。


更新:

Spring BootのJacksonバージョンとpom.xmlにあったバージョンとのバージョンの不一致であることが判明しました。 MilošとAndyが提案したように、正しいバージョンを設定してspring.jackson.serialization.write_dates_as_timestamps=trueでアプリを実行すると、ObjectMapperを構成したり、LocalDateTimeに注釈を追加したりすることなく、問題が解決しましたモデルフィールド。

    ...
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>1.3.6.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>1.3.6.RELEASE</version>
        </dependency>

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

        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
        </dependency>

    </dependencies>
14
sa125

NoSuchMethodErrorは、Jacksonのバージョンを混合しているためです。 Spring Boot 1.3.6はJackson 2.6.7を使用しており、jackson-datatype-jsr310の2.8.1を使用しています。

Spring Bootはjackson-datatype-jsr310を含むJacksonの依存関係管理を提供するため、pomからバージョンを削除する必要があります。別のバージョンのJacksonを使用する場合は、jackson.versionプロパティをオーバーライドする必要があります。

<properties>
    <jackson.version>2.8.1</jackson.version>
</properties>

これにより、ジャクソンのすべての依存関係が同じバージョンになり、バージョンの不一致による問題が回避されます。

必要に応じて、ObjectMapperを構成するJavaコードを削除することもできます。Java Timeモジュールは、クラスパスでタイムスタンプとして日付を書き込むことは、application.propertiesで設定できます:

spring.jackson.serialization.write-dates-as-timestamps=false
25
Andy Wilkinson

ObjectMapper Beanは、Springで取得するために@Primaryとしてマークする必要があります。または、JavaTimeModule Beanを作成するだけで、Springがそれをピックアップし、デフォルトのオブジェクトマッパーに追加します。

おそらくすでに見ていますが、 公式ドキュメントをご覧ください

5

ジャクソンのバージョンを混在させるため、エラーが発生します。 Spring Bootのバージョン1.3.6.RELEASEを使用しています。 Spring Bootバージョン2.x.x.RELEASEに移行する場合は、com.fasterxml.jackson.datatype依存関係をspring-boot-starter-json依存関係に置き換えることができます。このようにして、Spring Bootに正しいジャクソンバージョンを処理させることができます。

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-json</artifactId>
    </dependency>
1
Paul Rambags