Spring Boot基于Jackson注解处理多态RequestBody的转换方案咨询
这种场景不建议单独实现Parent到Child的转换器,你当前的Jackson配置已经可以根据请求中的type字段将请求体直接反序列化为对应的子类实例,额外做转换器只会增加冗余逻辑,不会解决编译期类型安全的问题,反而可能引入不必要的转换异常。
以下是3种可落地的解决方案,均能满足编译期类型安全的要求,你可以根据项目实际情况选择:
方案1:访问者模式(符合开闭原则,推荐)
如果允许对模型类做少量扩展,访问者模式是最优解,后续新增保单类型不需要修改原有判断逻辑,所有方法调用均为编译期校验。
- 定义访问者接口
public interface PolicyVisitor { void visit(AutoInsurance autoInsurance); void visit(LifeInsurance lifeInsurance); }
- 在Policy父类新增accept方法
// 原有注解和字段保持不变 public class Policy { public void accept(PolicyVisitor visitor) { throw new UnsupportedOperationException("不支持的保单类型"); } }
- 两个子类分别重写accept方法
// AutoInsurance类新增 @Override public void accept(PolicyVisitor visitor) { visitor.visit(this); } // LifeInsurance类新增 @Override public void accept(PolicyVisitor visitor) { visitor.visit(this); }
- 业务服务实现访问者接口
@Service public class PolicyService implements PolicyVisitor { @Override public void visit(AutoInsurance autoInsurance) { processAutoInsurance(autoInsurance); } @Override public void visit(LifeInsurance lifeInsurance) { processLifeInsurance(lifeInsurance); } // 原有业务方法保持不变 public void processAutoInsurance(AutoInsurance autoInsurance) {} public void processLifeInsurance(LifeInsurance lifeInsurance) {} }
- 控制器代码简化为
@PostMapping public void savePolicy(@RequestBody Policy policy) { policy.accept(policyService); }
方案2:拆分接口路由(无侵入,推荐)
如果模型类是swagger-codegen自动生成的,不想修改生成代码,可以直接在Spring MVC层根据type字段做路由,直接用子类作为接口参数:
@RestController @RequestMapping("/policy") public class PolicyController { @PostMapping(params = "type=AUTO_INSURANCE") public void saveAutoPolicy(@RequestBody AutoInsurance autoInsurance) { service.processAutoInsurance(autoInsurance); } @PostMapping(params = "type=LIFE_INSURANCE") public void saveLifePolicy(@RequestBody LifeInsurance lifeInsurance) { service.processLifeInsurance(lifeInsurance); } }
Spring MVC会自动根据请求参数/请求体中的type字段路由到对应方法,参数直接为子类类型,完全不需要做类型判断和转换。
方案3:Java 17+模式匹配(最小改动)
如果项目使用Java 17及以上版本,不需要修改任何现有结构,直接用模式匹配简化原有代码,不需要手动强转,也能避免强转错误:
@PostMapping public void savePolicy(@RequestBody Policy policy) { if (policy instanceof AutoInsurance autoInsurance) { service.processAutoInsurance(autoInsurance); } else if (policy instanceof LifeInsurance lifeInsurance) { service.processLifeInsurance(lifeInsurance); } }
内容的提问来源于stack exchange,提问作者Ryan Leung
相关产品推荐
相关产品推荐

