在使用Spring Boot Framework时,我遇到了Jackson的模型映射器的怪异问题。杰克逊有时似乎在从JSON有效负载映射到我的一个DTO时遇到问题。奇怪的是,只有当有问题的端点不是服务器启动时调用的第一个端点之一时,这种情况才会发生。这是错误:
2018-12-21 11:10:05.012 [http-nio-8080-exec-7] WARN o.s.w.s.m.s.DefaultHandlerExceptionResolver.handleHttpMessageNotReadable(384) - Failed to read HTTP message: org.springframework.http.converter.HttpMessageNotReadableException: Could not read JSON document: No _valueDeserializer assigned
at [Source: java.io.PushbackInputStream@22361a02; line: 1, column: 208] (through reference chain: c.r.p.a.d.s.ServiceProviderSubscriptionDTO["advisor"]->c.r.p.a.d.AdvisorDTO["lastModifiedBy"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: No _valueDeserializer assigned
at [Source: java.io.PushbackInputStream@22361a02; line: 1, column: 208] (through reference chain: c.r.p.a.d.s.ServiceProviderSubscriptionDTO["advisor"]->c.r.p.a.d.AdvisorDTO["lastModifiedBy"])
以下是发生此错误时调用的端点。仅当我在以下端点之前调用几个端点时,才会发生此错误。如果在服务器启动后我首先调用此端点,则它将正确成功。
/**
* POST /subscriptions/subscribe -> Create account subscription.
*
* @param serviceProviderSubscriptionDTO the subscription information
* @return the created subscription object
*/
@RequestMapping(value = "/subscriptions/subscribe", method = RequestMethod.POST)
@Timed
public ResponseEntity<?> subscribe(@RequestBody ServiceProviderSubscriptionDTO serviceProviderSubscriptionDTO) {
this.logger.error("Service Provider Subscription DTO: " + ReflectionToStringBuilder.toString(serviceProviderSubscriptionDTO));
try {
SubscriptionDTO result = this.service.create(serviceProviderSubscriptionDTO);
return ResponseEntity.ok().body(result);
} catch (Exception ex) {
ex.printStackTrace();
this.logger.error(ex.getMessage());
}
return ResponseEntity.badRequest().body(new ErrorDTO("SUBSCRIPTION_CREATE_FAILED"));
}
如果将控制器更改为仅接受通用映射,然后使用org.modelmapper.ModelMapper将其映射到ServiceProviderSubscriptionDTO,则无论何时调用端点,一切都可以正常工作。显然,这不是理想的解决方案,因为我失去了Spring Framework的RequestBody注释的所有好处。
/**
* POST /subscriptions/subscribe -> Create account subscription.
*
* @param serviceProviderSubscriptionDTO the subscription information
* @return the created subscription object
*/
@RequestMapping(value = "/subscriptions/subscribe", method = RequestMethod.POST)
@Timed
public ResponseEntity<?> subscribe(@RequestBody Map<String, Object> serviceProviderSubscriptionDTO) {
this.logger.error("Service Provider Subscription DTO: " + ReflectionToStringBuilder.toString(serviceProviderSubscriptionDTO));
try {
ServiceProviderSubscriptionDTO converted = this.modelMapper.map(serviceProviderSubscriptionDTO, ServiceProviderSubscriptionDTO.class);
SubscriptionDTO result = this.service.create(converted);
return ResponseEntity.ok().body(result);
} catch (Exception ex) {
ex.printStackTrace();
this.logger.error(ex.getMessage());
}
return ResponseEntity.badRequest().body(new ErrorDTO("SUBSCRIPTION_CREATE_FAILED"));
}
下面是DTO供参考。
服务提供商订阅DTO
@JsonIgnoreProperties(ignoreUnknown = true)
public class ServiceProviderSubscriptionDTO {
/**
* The payment source token.
*/
protected String paymentSourceToken;
/**
* The Advisor reference.
*/
@JsonIgnoreProperties("subscription")
private AdvisorDTO advisor;
public String getPaymentSourceToken() {
return this.paymentSourceToken;
}
public void setPaymentSourceToken(String paymentSourceToken) {
this.paymentSourceToken = paymentSourceToken;
}
public AdvisorDTO getAdvisor() {
return this.advisor;
}
public void setAdvisor(AdvisorDTO advisor) {
this.advisor = advisor;
}
}
订阅DTO
@JsonIgnoreProperties(ignoreUnknown = true)
public class SubscriptionDTO {
/**
* Database identification number.
*/
@Id
protected Long id;
/**
* First and last name of the user who created the record in database.
*/
protected String lastModifiedBy;
/**
* The Advisor reference.
*/
@JsonIgnoreProperties({ "subscription", "lastModifiedBy" })
private AdvisorDTO advisor;
/**
* The Service Provider Subscription.
*/
private ServiceProviderSubscriptionDTO serviceProviderSubscription;
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
public String getLastModifiedBy() {
return this.lastModifiedBy;
}
public void setLastModifiedBy(String lastModifiedBy) {
this.lastModifiedBy = lastModifiedBy;
}
public AdvisorDTO getAdvisor() {
return this.advisor;
}
public void setAdvisor(AdvisorDTO advisor) {
this.advisor = advisor;
}
public ServiceProviderSubscriptionDTO getServiceProviderSubscription() {
return this.serviceProviderSubscription;
}
public void setServiceProviderSubscription(ServiceProviderSubscriptionDTO serviceProviderSubscription) {
this.serviceProviderSubscription = serviceProviderSubscription;
}
}
DTO顾问
@JsonIgnoreProperties(ignoreUnknown = true)
public class AdvisorDTO {
/**
* Database identification number.
*/
@Id
protected Long id;
/**
* First and last name of the user who created the record in database.
*/
protected String lastModifiedBy;
/**
* The subscription.
*/
private SubscriptionDTO subscription;
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
public String getLastModifiedBy() {
return this.lastModifiedBy;
}
public void setLastModifiedBy(String lastModifiedBy) {
this.lastModifiedBy = lastModifiedBy;
}
public SubscriptionDTO getSubscription() {
return this.subscription;
}
public void setSubscription(SubscriptionDTO subscription) {
this.subscription = subscription;
}
}
在我看来,这似乎是某种模型映射缓存问题,其中其他端点正在为模型映射器缓存某种与此对象不兼容的指令。当将这些有效载荷读入控制器时,我不知道杰克逊如何处理这些有效载荷,因此我只能推测。这些错误是在我的任何控制器代码运行之前引发的。
有人对我有任何见解,可能是什么原因引起的以及如何解决?
Spring Boot:1.5.3。发布
Spring Core:4.3.8。发布
Jackson Core:2.8.8
Java:8