问题描述
通常在微服务中需要调用远程服务,假如服务A 调用服务B的接口,而服务B的接口中需要的参数是一个 List<抽象类>,由于List中保存的抽象类没有明确指向具体的子类或实现类,因此序列化会失败。
报错信息:com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of
xxx.xxx.xxx.Product
(no Creators, like default constructor, exist): abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information
服务B的接口
@ApiOperation(value = "计算产品价格")
@PostMapping("/calculatePrice")
Result<?> calculatePrice(@RequestBody List<Product> products);
抽象类 Product
@Data
public abstract class Product{
/**
* 产品名称
*/
private String name;
/**
* 产品类型
*/
private Integer type;
/**
* 产品价格
*/
private Long price;
}
实现类A
@Data
public class ProductA extends Product {
/**
* 产品规格
*/
private long spec;
/**
* 订单编号
*/
private String orderNo;
}
实现类B
@Data
public class ProductB extends Product {
/**
* 订单编号
*/
private String orderNo;
}
解决方案:
使用com.fasterxml.jackson.core的属性来解决上面问题
- @JsonSubTypes – indicates sub-types of the annotated type 指出被注解类型的子类
- @JsonTypeName – defines a logical type name to use for annotated class 定义被注解类使用的逻辑名称
1. 导入jackson坐标
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.5</version>
</dependency>
2. 改造抽象类及其实现类
抽象类 Product
@Data
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME)
@JsonSubTypes({
@JsonSubTypes.Type(value = ProductA.class, name = "A"),
@JsonSubTypes.Type(value = ProductB.class, name = "B"),
})
public abstract class Product{
/**
* 产品名称
*/
private String name;
/**
* 产品类型
*/
private Integer type;
/**
* 产品价格
*/
private Long price;
}
实现类A
@Data
@NoArgsConstructor
@JsonTypeName(value = "A")
public class ProductA extends Product {
/**
* 产品规格
*/
private long spec;
/**
* 订单编号
*/
private String orderNo;
}
实现类B
@Data
@NoArgsConstructor
@JsonTypeName(value = "B")
public class ProductB extends Product {
/**
* 订单编号
*/
private String orderNo;
}