首页 > 解决方案 > 间歇性 Jackson 模型映射器参考链错误

问题描述

在使用 Spring Boot 框架时,我遇到了 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.RELEASE

Spring核心:4.3.8.RELEASE

杰克逊核心:2.8.8

爪哇:8

标签: javaspringspring-bootjackson

解决方案


推荐阅读