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>
我正在努力将 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
.
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>