Spring Boot POST请求中抽象Die列表属性的反序列化异常解决咨询
问题原因
你遇到的异常是因为Jackson处理HTTP请求体的反序列化时,无法实例化抽象类Die——既没有无参构造器,Jackson也不知道该映射到哪个具体的骰子子类。注意:JPA的@Convert注解只负责实体与数据库字段的转换,和JSON的序列化/反序列化完全无关,所以得针对Jackson单独配置。
解决方案
方案一:用Jackson类型注解自动识别子类
在抽象类Die上添加Jackson的类型注解,让它能根据JSON中的字段自动匹配具体子类:
import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; @JsonTypeInfo( use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "color" // 对应请求体中每个Die对象的color字段 ) @JsonSubTypes({ @JsonSubTypes.Type(value = BlueDie.class, name = "BLUE"), @JsonSubTypes.Type(value = GreenDie.class, name = "GREEN"), @JsonSubTypes.Type(value = PurpleDie.class, name = "PURPLE"), @JsonSubTypes.Type(value = RedDie.class, name = "RED"), @JsonSubTypes.Type(value = YellowDie.class, name = "YELLOW") }) public abstract class Die { private int value; private dieColor color; // 新增protected无参构造器,Jackson反序列化需要 protected Die() {} public Die(int value) { this.value = value; } // 原有getter/setter保留 }
说明:只要请求体中的每个Die对象包含color字段(值和枚举dieColor的name一致),Jackson就会自动实例化对应的子类。
方案二:自定义Jackson反序列化器(适配字符串格式)
如果请求体中的骰子是用类似数据库存储的字符串格式(比如"R3B5"),可以写一个自定义反序列化器处理List<Die>:
- 编写反序列化器:
import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonDeserializer; import java.io.IOException; import java.util.ArrayList; import java.util.List; public class DieListDeserializer extends JsonDeserializer<List<Die>> { @Override public List<Die> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { String diceStr = p.getText(); String[] dice = diceStr.split("(?<=\\G.{2})"); List<Die> result = new ArrayList<>(); for (String die : dice) { switch (die.charAt(0)) { case 'B' -> result.add(new BlueDie(die.charAt(1) - '0')); case 'G' -> result.add(new GreenDie(die.charAt(1) - '0')); case 'P' -> result.add(new PurpleDie(die.charAt(1) - '0')); case 'R' -> result.add(new RedDie(die.charAt(1) - '0')); case 'Y' -> result.add(new YellowDie(die.charAt(1) - '0')); } } return result; } }
- 在
Game类的die字段上绑定反序列化器:
@Entity public class Game { // 其他字段保留 @Convert(converter = GameDiceConverter.class) @JsonDeserialize(using = DieListDeserializer.class) // 新增该注解 private List<Die> die; // 原有getter/setter保留 }
这样请求体中的die字段如果是字符串格式,Jackson会自动转成List<Die>。
方案三:配合@JsonCreator优化构造器
如果请求体中的每个Die是对象格式(比如{"color":"RED", "value":3}),可以给Die的构造器添加@JsonCreator注解,让Jackson直接用带参构造器实例化:
import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; public abstract class Die { private int value; private dieColor color; @JsonCreator public Die(@JsonProperty("value") int value, @JsonProperty("color") dieColor color) { this.value = value; this.color = color; } // 原有getter/setter保留 }
说明:该方案配合方案一的类型注解使用效果最佳,能同时解决子类识别和构造器问题。
内容的提问来源于stack exchange,提问作者Niels
相关产品推荐
相关产品推荐

