Spring 使用 Jackson 将 java.time.LocalDateTime 序列化为 return ISO-8601 JSON 时间戳时出现引导问题?

Spring Boot issues serializing java.time.LocalDateTime with Jackson to return ISO-8601 JSON timestamps?

我正在努力将 spring-boot REST API 应用程序中的某些模型转换为使用 java 8 的 java.time.LocalDateTime 而不是 joda 的 DateTime .我希望从 API 调用返回的时间戳符合 ISO_8601 格式。动机是向前兼容 Java 8 的时间 (more here).

证明困难的部分是将包含 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 以关闭日期作为时间戳 jackson 功能:

spring.jackson.serialization.WRITE_DATES_AS_TIMESTAMPS = false

我的专家部门:

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

另外,我还在配置 class:

中配置了应用程序的 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>

您的 ObjectMapper bean 必须标记为 @Primary 才能被 Spring 拾取。或者,您可以只创建一个 JavaTimeModule bean,它会被 Spring 拾取并添加到默认对象映射器。

您可能已经看过了,但是 take a look at the official documentation

NoSuchMethodError 是因为您正在混合 Jackson 的版本。 Spring Boot 1.3.6 使用 Jackson 2.6.7 而您使用的是 jackson-datatype-jsr310.

的 2.8.1

Spring Boot 为 Jackson 提供了依赖管理,包括 jackson-datatype-jsr310,所以你应该从你的 pom.xml 中删除版本。如果你想使用不同版本的 Jackson,你应该覆盖 jackson.version 属性:

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

这将确保您所有的 Jackson 依赖项都具有相同的版本,从而避免版本不匹配的问题。

如果您愿意,您也可以删除配置 ObjectMapper 的 Java 代码。 Java 时间模块在类路径中时会自动注册,并且可以在 application.properties:

中配置将日期写为时间戳
spring.jackson.serialization.write-dates-as-timestamps=false

错误发生是因为您混用了 Jackson 的版本。您正在使用 Spring Boot 的 1.3.6.RELEASE 版本。如果您要迁移到 Spring 引导版本 2.x.x.RELEASE,那么您可以将 com.fasterxml.jackson.datatype 依赖项替换为 spring-boot-starter-json 依赖项。通过这种方式,您可以让 Spring Boot 处理正确的 Jackson 版本。

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