Spring Boot请求嵌套类反序列化问题及注解方案咨询
Spring Boot请求嵌套类反序列化问题
在Spring Boot中处理请求反序列化时,遇到第一层属性正常映射,但嵌套字段无法映射到对应子类的问题。
相关代码
@Getter @Setter @NoArgsConstructor @AllArgsConstructor public class CustomForm extends GenericJson { private String formId; private CustomInfo info; private List<CustomItem> items = new ArrayList<>(); private String linkedSheetId; private String responderUri; private String revisionId; private FormSettings settings; public CustomForm(Form form){ BeanUtils.copyProperties(form, this); if(form.getInfo() != null){ this.info = new CustomInfo(form.getInfo()); } if(form.getItems() != null){ for(Item item:form.getItems()){ this.items.add(new CustomItem(item)); } } } public Form getForm(){ Form form = new Form(); BeanUtils.copyProperties(this, form); List<Item> items = new ArrayList<>(); for(CustomItem item:this.items){ items.add(item.getItem()); } form.setItems(items); if(!this.info.isEmpty()) { form.setInfo(this.info.getInfo()); } return form; } }
请求示例
{ "formId": "1234", "info": { "documentTitle": "Untitled form", "title": "prova" }, "items": [ { "itemId": "123", "questionItem": { "question": { "choiceQuestion": { "options": [ { "value": "Newsletter" }, { "value": "Magazine" }, { "value": "Social Network" }, { "value": "Siti" }, { "value": "Associazioni di categoria" }, { "value": "Aziende partner" }, { "value": "Comunicazione interna all'azienda" } ], "type": "DROP_DOWN" }, "questionId": "123" } }, "title": "Come sei venuto a conoscenza di questo Corso?" }, { "itemId": "123", "questionGroupItem": { "grid": { "columns": { "options": [ { "value": "PESSIMO" }, { "value": "MEDIOCRE" }, { "value": "SUFFICIENTE" }, { "value": "BUONO" }, { "value": "OTTIMO" } ], "type": "RADIO" } }, "questions": [ { "questionId": "123", "rowQuestion": { "title": "Pulizia delle aule" } }, { "questionId": "123", "rowQuestion": { "title": "Materiale fornito" } }, { "questionId": "123", "rowQuestion": { "title": "Competenza docente" } }, { "questionId": "123", "rowQuestion": { "title": "Completezza contenuti" } }, { "questionId": "123", "rowQuestion": { "title": "Applicabilità delle nozioni" } }, { "questionId": "123", "rowQuestion": { "title": "Rispondenza ad aspettative" } }, { "questionId": "123", "rowQuestion": { "title": "Gentilezza del personale" } } ] } } ], "responderUri": "https://example.om", "revisionId": "00000005" }
提问:是否存在注解可将请求字段与对应嵌套类关联?
解决方案
可以通过Jackson的注解解决嵌套类的反序列化映射问题,以下是关键注解和注意事项:
1. 基础字段映射:@JsonProperty
如果请求字段名与嵌套类属性名存在差异(比如大小写、驼峰/下划线格式不同),直接在嵌套类的属性上添加@JsonProperty指定对应JSON字段名。示例:
@Getter @Setter @NoArgsConstructor public class CustomInfo { @JsonProperty("documentTitle") private String documentTitle; @JsonProperty("title") private String title; }
若字段名完全匹配,该注解可省略,但必须确保嵌套类有无参构造方法(Jackson反序列化的必要条件),且属性配有@Getter/@Setter或公有的getter/setter方法。
2. 多态嵌套类处理:@JsonTypeInfo + @JsonSubTypes
如果CustomItem是父类,请求中的questionItem、questionGroupItem对应不同子类,需要用这两个注解指定类型识别规则。示例:
@Getter @Setter @NoArgsConstructor @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "itemType") @JsonSubTypes({ @JsonSubTypes.Type(value = QuestionItem.class, name = "questionItem"), @JsonSubTypes.Type(value = QuestionGroupItem.class, name = "questionGroupItem") }) public class CustomItem { private String itemId; private String title; private String itemType; // 用于标识子类类型的字段 }
通过JSON中指定的字段区分要实例化的子类,确保不同类型的嵌套对象能正确反序列化。
3. 核心注意事项
- 所有嵌套类(
CustomInfo、CustomItem、FormSettings等)必须添加@NoArgsConstructor,Jackson依赖无参构造创建对象。 - 嵌套类的所有属性必须配有getter/setter方法(可通过Lombok的
@Getter/@Setter快速实现)。 - 检查
GenericJson类是否覆盖了Jackson的默认序列化逻辑,避免干扰嵌套类的映射处理。
内容的提问来源于stack exchange,提问作者Luca Pisoni
相关产品推荐
相关产品推荐

