Jackson 从 ISO DateTime 反序列化 Joda LocalDate
Jackson to deserialize Joda LocalDate from ISO DateTime
我正在使用 Angular 日期选择器向我的 MVC 控制器发送一个日期,使用 Javascript 日期对象,它是一个 ISO 日期/时间 .
反序列化 java.util.Date
它就像一个魅力,Hibernate 会关心在插入记录时将 Date
时间缩短为普通日期。
但现在我正在从 java.util.Date
过渡到 org.joda.time.[APPROPRIATE_CLASS_HERE]
,我面临着这个反序列化问题。
据我了解,如果我在我的 DTO 中强制使用 DateTime
,Jackson 将正确反序列化它们,而我更喜欢在目标类型为日期时删除时间信息。
例如
public class UserDto {
private LocaLDate passwordExpirationDate;
}
{
"username":"9493",
"completeName":"ljdjf",
"email":"wesf@dsgfds",
"cultureId":"IT",
"enabled":false,
"passwordExpirationDate":"2017-07-13T10:00:00.000Z",
"accountExpirationDate":"2017-07-20T10:00:00.000Z"
}
相反,我得到了这个:
org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Invalid format: "2017-07-13T10:00:00.000Z" is malformed at "T10:00:00.000Z"; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Invalid format: "2017-07-13T10:00:00.000Z" is malformed at "T10:00:00.000Z" (through reference chain: it.phoenix.web.data.dtos.admin.profile.UserDTO["passwordExpirationDate"])
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:244) ~[spring-web-4.3.9.RELEASE.jar:4.3.9.RELEASE]
Caused by: com.fasterxml.jackson.databind.JsonMappingException: Invalid format: "2017-07-13T10:00:00.000Z" is malformed at "T10:00:00.000Z" (through reference chain: it.phoenix.web.data.dtos.admin.profile.UserDTO["passwordExpirationDate"])
at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:388) ~[jackson-databind-2.8.9.jar:2.8.9]
Caused by: java.lang.IllegalArgumentException: Invalid format: "2017-07-13T10:00:00.000Z" is malformed at "T10:00:00.000Z"
at org.joda.time.format.DateTimeFormatter.parseLocalDateTime(DateTimeFormatter.java:900) ~[joda-time-2.9.9.jar:2.9.9]
at org.joda.time.format.DateTimeFormatter.parseLocalDate(DateTimeFormatter.java:844) ~[joda-time-2.9.9.jar:2.9.9]
at com.fasterxml.jackson.datatype.joda.deser.LocalDateDeserializer.deserialize(LocalDateDeserializer.java:39) ~[jackson-datatype-joda-2.8.9.jar:2.8.9]
at com.fasterxml.jackson.datatype.joda.deser.LocalDateDeserializer.deserialize(LocalDateDeserializer.java:15) ~[jackson-datatype-joda-2.8.9.jar:2.8.9]
at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:504) ~[jackson-databind-2.8.9.jar:2.8.9]
at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:104) ~[jackson-databind-2.8.9.jar:2.8.9]
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:357) ~[jackson-databind-2.8.9.jar:2.8.9]
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:148) ~[jackson-databind-2.8.9.jar:2.8.9]
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3814) ~[jackson-databind-2.8.9.jar:2.8.9]
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2938) ~[jackson-databind-2.8.9.jar:2.8.9]
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:241) ~[spring-web-4.3.9.RELEASE.jar:4.3.9.RELEASE]
... 92 more
问题是:是否有一种聪明的方法让 Jackson 可以通过简单地剥离 default/current 时区的时间部分将 DateTime 对象解码为 Joda LocalDate
?
备注:
- 我已经有 Jackson Joda 模块依赖
- 杰克逊是 2.8.9
- 我被迫使用 Java 7。在相关的 Java 8 项目中,我对 java.time
东西(和 Jackson JSR310 模块)没有这样的问题
根据错误消息,date/time 输入为 2017-07-13T10:00:00.000Z
,默认情况下 LocalDate
无法处理它。
您可以使用 LocalDate
字段中的 com.fasterxml.jackson.annotation.JsonFormat
注释配置此格式:
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSZ")
private LocalDate passwordExpirationDate;
这将使 Jackson 正确解析日期。
以下内容在我的 Spring 上下文配置中对我有用
<bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean" id="pnxObjectMapper">
<property name="deserializersByType">
<map key-type="java.lang.Class">
<entry>
<key>
<value>org.joda.time.LocalDate</value>
</key>
<bean class="com.fasterxml.jackson.datatype.joda.deser.LocalDateDeserializer">
<constructor-arg>
<util:constant static-field="com.fasterxml.jackson.datatype.joda.cfg.FormatConfig.DEFAULT_DATETIME_PARSER" />
</constructor-arg>
</bean>
</entry>
</map>
</property>
</bean>
说明:在加载 JodaModule 之前,它为 LocalDate
定义了一个反序列化器,正确地采用了 ISO date-only 格式,我强制 Spring 在构建序列化器时更改格式化程序
我想你在创建时 ObjectMapper
你可以注册一些模块。
public ObjectMapper objectMapper() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
objectMapper.registerModule(new JavaTimeModule());
objectMapper.registerModule(new JodaModule());
return objectMapper;
}
并将其放入 Spring 配置中的消息转换器
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setObjectMapper(objectMapper());
// Configuration class
@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(mappingJackson2HttpMessageConverter());
}
在它应该工作之后
我正在使用 Angular 日期选择器向我的 MVC 控制器发送一个日期,使用 Javascript 日期对象,它是一个 ISO 日期/时间 .
反序列化 java.util.Date
它就像一个魅力,Hibernate 会关心在插入记录时将 Date
时间缩短为普通日期。
但现在我正在从 java.util.Date
过渡到 org.joda.time.[APPROPRIATE_CLASS_HERE]
,我面临着这个反序列化问题。
据我了解,如果我在我的 DTO 中强制使用 DateTime
,Jackson 将正确反序列化它们,而我更喜欢在目标类型为日期时删除时间信息。
例如
public class UserDto {
private LocaLDate passwordExpirationDate;
}
{
"username":"9493",
"completeName":"ljdjf",
"email":"wesf@dsgfds",
"cultureId":"IT",
"enabled":false,
"passwordExpirationDate":"2017-07-13T10:00:00.000Z",
"accountExpirationDate":"2017-07-20T10:00:00.000Z"
}
相反,我得到了这个:
org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Invalid format: "2017-07-13T10:00:00.000Z" is malformed at "T10:00:00.000Z"; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Invalid format: "2017-07-13T10:00:00.000Z" is malformed at "T10:00:00.000Z" (through reference chain: it.phoenix.web.data.dtos.admin.profile.UserDTO["passwordExpirationDate"])
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:244) ~[spring-web-4.3.9.RELEASE.jar:4.3.9.RELEASE]
Caused by: com.fasterxml.jackson.databind.JsonMappingException: Invalid format: "2017-07-13T10:00:00.000Z" is malformed at "T10:00:00.000Z" (through reference chain: it.phoenix.web.data.dtos.admin.profile.UserDTO["passwordExpirationDate"])
at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:388) ~[jackson-databind-2.8.9.jar:2.8.9]
Caused by: java.lang.IllegalArgumentException: Invalid format: "2017-07-13T10:00:00.000Z" is malformed at "T10:00:00.000Z"
at org.joda.time.format.DateTimeFormatter.parseLocalDateTime(DateTimeFormatter.java:900) ~[joda-time-2.9.9.jar:2.9.9]
at org.joda.time.format.DateTimeFormatter.parseLocalDate(DateTimeFormatter.java:844) ~[joda-time-2.9.9.jar:2.9.9]
at com.fasterxml.jackson.datatype.joda.deser.LocalDateDeserializer.deserialize(LocalDateDeserializer.java:39) ~[jackson-datatype-joda-2.8.9.jar:2.8.9]
at com.fasterxml.jackson.datatype.joda.deser.LocalDateDeserializer.deserialize(LocalDateDeserializer.java:15) ~[jackson-datatype-joda-2.8.9.jar:2.8.9]
at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:504) ~[jackson-databind-2.8.9.jar:2.8.9]
at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:104) ~[jackson-databind-2.8.9.jar:2.8.9]
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:357) ~[jackson-databind-2.8.9.jar:2.8.9]
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:148) ~[jackson-databind-2.8.9.jar:2.8.9]
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3814) ~[jackson-databind-2.8.9.jar:2.8.9]
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2938) ~[jackson-databind-2.8.9.jar:2.8.9]
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:241) ~[spring-web-4.3.9.RELEASE.jar:4.3.9.RELEASE]
... 92 more
问题是:是否有一种聪明的方法让 Jackson 可以通过简单地剥离 default/current 时区的时间部分将 DateTime 对象解码为 Joda LocalDate
?
备注:
- 我已经有 Jackson Joda 模块依赖
- 杰克逊是 2.8.9
- 我被迫使用 Java 7。在相关的 Java 8 项目中,我对 java.time
东西(和 Jackson JSR310 模块)没有这样的问题
根据错误消息,date/time 输入为 2017-07-13T10:00:00.000Z
,默认情况下 LocalDate
无法处理它。
您可以使用 LocalDate
字段中的 com.fasterxml.jackson.annotation.JsonFormat
注释配置此格式:
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSZ")
private LocalDate passwordExpirationDate;
这将使 Jackson 正确解析日期。
以下内容在我的 Spring 上下文配置中对我有用
<bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean" id="pnxObjectMapper">
<property name="deserializersByType">
<map key-type="java.lang.Class">
<entry>
<key>
<value>org.joda.time.LocalDate</value>
</key>
<bean class="com.fasterxml.jackson.datatype.joda.deser.LocalDateDeserializer">
<constructor-arg>
<util:constant static-field="com.fasterxml.jackson.datatype.joda.cfg.FormatConfig.DEFAULT_DATETIME_PARSER" />
</constructor-arg>
</bean>
</entry>
</map>
</property>
</bean>
说明:在加载 JodaModule 之前,它为 LocalDate
定义了一个反序列化器,正确地采用了 ISO date-only 格式,我强制 Spring 在构建序列化器时更改格式化程序
我想你在创建时 ObjectMapper
你可以注册一些模块。
public ObjectMapper objectMapper() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
objectMapper.registerModule(new JavaTimeModule());
objectMapper.registerModule(new JodaModule());
return objectMapper;
}
并将其放入 Spring 配置中的消息转换器
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setObjectMapper(objectMapper());
// Configuration class
@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(mappingJackson2HttpMessageConverter());
}
在它应该工作之后