Java Spring中如何创建支持动态类型参数的API端点
问题根源
你遇到的错误是因为Jackson无法实例化抽象类ImportModel。当反序列化createList和updateList时,JSON中没有提供足够的类型信息来指示每个列表项应该映射到ImportTypeAModel还是ImportTypeBModel,导致Jackson不知道该创建哪个具体子类的实例。
解决方案一:控制器侧类型解析
这种方法先读取原始JSON,提取entityType后再将请求转换为对应的泛型类型,逻辑直观且易于维护:
修改控制器方法:
@RequestMapping(method = RequestMethod.POST, value = "/import") public void executeImport(@RequestBody JsonNode requestNode) throws JsonProcessingException { ObjectMapper mapper = new ObjectMapper(); String entityType = requestNode.get("entityType").asText(); switch (entityType) { case "A": ImportRequest<ImportTypeAModel> typeARequest = mapper.convertValue( requestNode, TypeFactory.defaultInstance().constructParametricType(ImportRequest.class, ImportTypeAModel.class) ); processTypeAImport(typeARequest); break; case "B": ImportRequest<ImportTypeBModel> typeBRequest = mapper.convertValue( requestNode, TypeFactory.defaultInstance().constructParametricType(ImportRequest.class, ImportTypeBModel.class) ); processTypeBImport(typeBRequest); break; default: throw new IllegalArgumentException("Unsupported entity type: " + entityType); } } private void processTypeAImport(ImportRequest<ImportTypeAModel> request) { // 处理类型A的导入逻辑 for (ImportTypeAModel item : request.getCreateList()) { // 直接访问item.getRow()、item.getName()等属性 } } private void processTypeBImport(ImportRequest<ImportTypeBModel> request) { // 处理类型B的导入逻辑 for (ImportTypeBModel item : request.getCreateList()) { // 直接访问item.getFirstName()、item.getPhone()等属性 } }
解决方案二:自定义Jackson反序列化器
如果希望将反序列化逻辑从控制器中解耦,可以创建自定义反序列化器:
- 为
ImportRequest添加反序列化器注解:
@JsonDeserialize(using = ImportRequestDeserializer.class) public class ImportRequest<T extends ImportModel> { private String entityType; private List<T> createList; private List<T> updateList; // Getters和Setters public String getEntityType() { return entityType; } public void setEntityType(String entityType) { this.entityType = entityType; } public List<T> getCreateList() { return createList; } @SuppressWarnings("unchecked") public void setCreateList(List<? extends ImportModel> createList) { this.createList = (List<T>) createList; } public List<T> getUpdateList() { return updateList; } @SuppressWarnings("unchecked") public void setUpdateList(List<? extends ImportModel> updateList) { this.updateList = (List<T>) updateList; } }
- 实现自定义反序列化器:
public class ImportRequestDeserializer extends StdDeserializer<ImportRequest<? extends ImportModel>> { protected ImportRequestDeserializer() { super(ImportRequest.class); } @Override public ImportRequest<? extends ImportModel> deserialize(JsonParser parser, DeserializationContext context) throws IOException { ObjectMapper mapper = (ObjectMapper) parser.getCodec(); JsonNode rootNode = mapper.readTree(parser); String entityType = rootNode.get("entityType").asText(); Class<? extends ImportModel> modelClass = resolveModelClass(entityType); ImportRequest<?> request = new ImportRequest<>(); request.setEntityType(entityType); // 反序列化createList JsonNode createListNode = rootNode.get("createList"); List<? extends ImportModel> createList = mapper.convertValue( createListNode, TypeFactory.defaultInstance().constructCollectionType(List.class, modelClass) ); request.setCreateList(createList); // 反序列化updateList JsonNode updateListNode = rootNode.get("updateList"); List<? extends ImportModel> updateList = mapper.convertValue( updateListNode, TypeFactory.defaultInstance().constructCollectionType(List.class, modelClass) ); request.setUpdateList(updateList); return request; } private Class<? extends ImportModel> resolveModelClass(String entityType) { return switch (entityType) { case "A" -> ImportTypeAModel.class; case "B" -> ImportTypeBModel.class; default -> throw new IllegalArgumentException("Unsupported entity type: " + entityType); }; } }
- 保持原控制器方法,根据
entityType强转列表项:
@RequestMapping(method = RequestMethod.POST, value = "/import") public void executeImport(@RequestBody ImportRequest<? extends ImportModel> request) { switch (request.getEntityType()) { case "A": for (ImportModel item : request.getCreateList()) { ImportTypeAModel typeAItem = (ImportTypeAModel) item; // 处理类型A的项 } break; case "B": for (ImportModel item : request.getCreateList()) { ImportTypeBModel typeBItem = (ImportTypeBModel) item; // 处理类型B的项 } break; default: throw new IllegalArgumentException("Unsupported entity type"); } }
两种方案都能解决反序列化问题,核心是根据entityType明确告诉Jackson应该使用哪个具体的ImportModel子类。
内容的提问来源于stack exchange,提问作者theedchen
相关产品推荐
相关产品推荐

