编辑:
为了澄清问题我已经制作了一个图表:
我一直在迁移自定义Jetty Web服务以使用Spring REST模板,并且我遇到了以下解串器的问题。
自定义日期格式如下所示:"2016-10-18"
我需要在调用此自定义Date
类型的构造函数之前将其转换为3个整数。
之前这是有效的,因为我们刚刚通过服务ObjectMapper
并注册了反序列化程序,并且没有任何问题调用deserialize
。
现在我收到错误,因为杰克逊试图在我的自定义String
类型上调用一个Date
构造函数,但这种构造函数并不存在。该库不是由我维护的,因此我无法添加此构造函数。
错误:
"无法读取HTTP消息: org.springframework.http.converter.HttpMessageNotReadableException: 无法读取文档:无法实例化类型的值[简单 来自String值的type,class com.intercorp.domain.date.Date] (' 2016年9月30日&#39);没有单字符串构造函数/工厂方法
注释我尝试序列化的属性有效,但我不认为这是一个解决方案,因为注册deserialiser应检测类型并调用自身。 我更感兴趣的是为什么这不起作用而不是切换到注释:
@JsonDeserialize(using=JacksonConfig.CustomDateDeserializer.class)
private Date paymentDate;
我有以下Spring配置:
@Import({JacksonConfig.class})
public class WebServiceConfig {
@Autowired
private MappingJackson2HttpMessageConverter jacksonConverter;
@Bean
public MyWebService MyWebService () {
RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(jacksonConverter);
return new MyWebService(restTemplate);
}
}
JacksonConfig.class
@Configuration
public class JacksonConfig {
@Bean
public MappingJackson2HttpMessageConverter jacksonConverter() {
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setObjectMapper(objectMapper());
return converter;
}
@Bean
@Primary
public ObjectMapper objectMapper() {
Jackson2ObjectMapperBuilder mapperBuilder = new Jackson2ObjectMapperBuilder();
mapperBuilder.modules(myModule()).timeZone(TimeZone.getTimeZone("UTC"))
.featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
return mapperBuilder.build();
}
@Bean
public Module myModule() {
SimpleModule module = new SimpleModule("myModule", new Version(0, 0, 1, null));
module.addSerializer(new CustomDateSerializer());
//not Java Date - custom Date...
module.addDeserializer(Date.class, new CustomDateDeserializer());
return module;
}
// breakpoints indicate this is never called
static public class CustomDateDeserializer extends JsonDeserializer<Date> {
@Override
@SneakyThrows
public Date deserialize(JsonParser jp, DeserializationContext ctxt) {
String text = jp.getText();
if (text == null) {
return null;
}
if (text.length() >= 10) {
int year = parseInt(text.substring(0, 4));
int month = parseInt(text.substring(5, 7));
int day = parseInt(text.substring(8, 10));
return new Date(year, month, day);
}
// deserialize json object
else if (JsonToken.START_OBJECT.equals(jp.getCurrentToken())) {
JsonNode dateNode = jp.getCodec().readTree(jp);
return getDate(dateNode);
}
else {
return new Date(Integer.parseInt(text));
}
}
}
}
PaymentStatus.java
package com.otpp.memberapi.service.iaccess.data.pension;
import com.intercorp.domain.date.Date;
import com.intercorp.domain.money.Money;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class PensionPaymentStatus {
private boolean available;
private Money netMonthly;
//this date fails to deserialise
private Date paymentDate;
private boolean suspended;
}
示例JSON有效负载
{
"available": true,
"netMonthly": "1000.00",
"paymentDate": "2016-10-19",
"suspended": false
}
日期类很大,只包含Joda时间(用于Java8之前的envs)。它有几个构造函数,我试图使用的是YYYY,MM,DD整数构造函数。
答案 0 :(得分:1)
似乎请求未被转换器反序列化。
RestTemplate的no-arg构造函数使用默认转换器初始化它,相关代码段:
....
if (jackson2Present) {
this.messageConverters.add(new MappingJackson2HttpMessageConverter());
}
....
因为它使用&#39;首先赢得&#39;寻找合适的转换器的策略它永远不会使用你的,因为它位于列表的后面。
您需要更改:
RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(jacksonConverter);
对于这样的事情:
RestTemplate restTemplate = new RestTemplate(Collections.singletonList(jacksonConverter));
取决于您是否需要其他转换器。