You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot升级至3.4.5后Jackson反序列化ResponseTO接口报错求助

Spring Boot 3.4.5升级后Jackson反序列化第三方接口报错解决

问题现象

将Spring Boot从3.2.4升级至3.4.5后,接口接收请求时抛出Jackson反序列化错误:

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `****.ResponseTO` (no Creators, like default constructor, exist): abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information
at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); line: 1, column: 341] (through reference chain: *****.OperationResult["response"])

相关代码:

@RestController
@RequestMapping("/api/operations")
public class OperationController {

    @PostMapping
    public ResponseEntity<String> testCall(@RequestBody OperationResult operationResult) {
        log.info("Operation Name :: {}", operationResult.getOperationName());
        return ResponseEntity.ok("success");
    }
}
import lombok.*;

@Builder
@ToString
@EqualsAndHashCode
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class OperationResult {
    private Long id;
    private Long operationName;

    // 第三方提供的接口,存在多个具体实现类
    private ResponseTO response;
}

原因分析

ResponseTO是第三方库提供的接口/抽象类,Jackson反序列化OperationResult的response字段时,无法自动推断应该使用哪个具体实现类实例化。Spring Boot 3.4.x对应的Jackson版本升级后,默认反序列化策略对抽象类型的处理更严格,导致之前可能隐式生效的兼容逻辑不再起作用。

解决方案

1. 指定默认实现类(适用于单一实现场景)

如果ResponseTO只有一个常用的具体实现类,直接在字段上添加@JsonDeserialize注解指定实现类:

import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import lombok.*;

@Builder
@ToString
@EqualsAndHashCode
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class OperationResult {
    private Long id;
    private Long operationName;

    // 指定具体实现类
    @JsonDeserialize(as = ConcreteResponseTO.class)
    private ResponseTO response;
}

2. 自定义反序列化器(适用于多实现动态判断场景)

如果存在多个ResponseTO实现类,且需要根据请求JSON的字段动态判断,编写自定义反序列化器:

步骤1:实现自定义反序列化器

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;

import java.io.IOException;

public class ResponseTODeserializer extends JsonDeserializer<ResponseTO> {
    @Override
    public ResponseTO deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        JsonNode node = p.getCodec().readTree(p);
        // 根据JSON中的标识字段判断使用哪个实现类
        String type = node.get("type").asText();
        return switch (type) {
            case "TYPE_A" -> ctxt.readValue(node.traverse(p.getCodec()), ResponseTOImplA.class);
            case "TYPE_B" -> ctxt.readValue(node.traverse(p.getCodec()), ResponseTOImplB.class);
            default -> throw new IllegalArgumentException("Unsupported ResponseTO type: " + type);
        };
    }
}

步骤2:注册反序列化器

在OperationResult的字段上指定自定义反序列化器:

@JsonDeserialize(using = ResponseTODeserializer.class)
private ResponseTO response;

3. 使用Jackson混合注解(适用于多实现+类型标识场景)

如果请求JSON中包含类型标识字段,且无法修改第三方ResponseTO接口源码,使用Jackson的MixIn功能添加类型识别注解:

步骤1:定义MixIn接口

import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;

abstract class ResponseTOMixIn {
    @JsonTypeInfo(
            use = JsonTypeInfo.Id.NAME,
            include = JsonTypeInfo.As.PROPERTY,
            property = "type" // JSON中标识类型的字段名
    )
    @JsonSubTypes({
            @JsonSubTypes.Type(value = ResponseTOImplA.class, name = "TYPE_A"),
            @JsonSubTypes.Type(value = ResponseTOImplB.class, name = "TYPE_B")
    })
    abstract void dummyMethod(); // 无需实现,仅用于承载注解
}

步骤2:配置Jackson注册MixIn

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.fasterxml.jackson.databind.ObjectMapper;

@Configuration
public class JacksonConfig {
    @Bean
    public ObjectMapper objectMapper() {
        ObjectMapper mapper = new ObjectMapper();
        // 为第三方接口绑定MixIn注解
        mapper.addMixIn(ResponseTO.class, ResponseTOMixIn.class);
        return mapper;
    }
}

4. 全局配置类型映射(适用于全局统一处理)

如果需要全局为ResponseTO指定默认实现,在Spring Boot配置类中设置Jackson的类型映射:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.fasterxml.jackson.databind.ObjectMapper;

@Configuration
public class JacksonConfig {
    @Bean
    public ObjectMapper objectMapper() {
        ObjectMapper mapper = new ObjectMapper();
        // 全局指定ResponseTO的默认实现类
        mapper.registerSubtypes(ConcreteResponseTO.class);
        return mapper;
    }
}

内容的提问来源于stack exchange,提问作者nitinty

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 18:12:43