Spring Boot与Jackson一起串行化java.time.LocalDateTime以返回ISO-8601 JSON时间戳?

问题描述 投票:14回答:3

我正在努力在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来关闭日期作为时间戳杰克逊功能:

spring.jackson.serialization.WRITE_DATES_AS_TIMESTAMPS = false

我的maven deps:

<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>
serialization spring-boot java-8 jackson java-time
3个回答
24
投票

NoSuchMethodError是因为你混合了Jackson的版本。 Spring Boot 1.3.6使用Jackson 2.6.7,你使用2.8.1的jackson-datatype-jsr310

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

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

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

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

spring.jackson.serialization.write-dates-as-timestamps=false

5
投票

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

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


1
投票

发生错误的原因是您混合了Jackson的版本。您正在使用Spring Boot的1.3.6.RELEASE版本。如果您要迁移到Spring Boot版本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>
© www.soinside.com 2019 - 2024. All rights reserved.