Jackson序列化时属性名定义冲突问题求助
问题详情
我有一个AusgangsrechnungGeneral类,包含属性abrechnungsmonat。此前通过Jackson从JSON反序列化时,JSON中的abrechnungsMonat能正常映射到该属性。现在需要实现:
- 反序列化:JSON的
abrechnungsMonat映射到类的abrechnungsmonat属性 - 序列化:输出JSON的属性名为
abrechnungsmonat
编写的代码片段如下:
@JsonFormat(pattern="yyyy-MM") @JsonDeserialize(using = YearMonthDeserializer.class) @JsonSetter("abrechnungsMonat") private YearMonth abrechnungsmonat; @JsonGetter("abrechnungsmonat") public YearMonth getAbrechnungsmonat() { return this.abrechnungsmonat; }
该方式对其他属性有效,但此处抛出错误:
java.lang.IllegalStateException: Conflicting/ambiguous property name definitions (implicit name 'abrechnungsmonat'): found multiple explicit names: [abrechnungsmonat, abrechnungsMonat], but also implicit accessor: [field com.itf.ghost.propartsyncservice.api.rechnung.propartmodel.AusgangsrechnungGeneral#abrechnungsmonat][visible=true,ignore=false,explicitName=false]
使用了Lombok的@Data注解,手动定义了getter,按理解Lombok不会额外生成。完整类代码:
@NoArgsConstructor @AllArgsConstructor @Data @ToString(callSuper = true) @SuperBuilder @JsonIgnoreProperties(ignoreUnknown = true) public class AusgangsrechnungGeneral extends Rechnung { @JsonSetter("leistungsZeitraum") private String leistungszeitraum; @JsonGetter("leistungszeitraum") public String getLeistugnszeitraum() { return this.leistungszeitraum; } private String filePath; private Boolean isProberechnung; @JsonFormat(pattern="yyyy-MM-dd") @JsonDeserialize(using = LocalDateDeserializer.class) private LocalDate bezahltAm; @JsonFormat(pattern="yyyy-MM-dd") @JsonDeserialize(using = LocalDateDeserializer.class) private LocalDate zahlungErwartetAm; @JsonFormat(pattern="yyyy-MM") @JsonDeserialize(using = YearMonthDeserializer.class) @JsonSetter("abrechnungsMonat") private YearMonth abrechnungsmonat; @JsonGetter("abrechnungsmonat") public YearMonth getAbrechnungsmonat() { return this.abrechnungsmonat; } @JsonSetter("kundenId") private Long kunde; @JsonGetter("kunde") public Long getKunde() { return this.kunde; } @JsonSetter("abls") private List<AbrechenbareLeistung> abrechenbareLeistungen; @JsonGetter("abrechenbareLeistungen") public List<AbrechenbareLeistung> getAbrechenbareLeistungen() { return this.abrechenbareLeistungen; } }
错误原因
Jackson同时识别到了三个属性名来源:
- 字段本身的隐式属性名
abrechnungsmonat @JsonSetter指定的abrechnungsMonat@JsonGetter指定的abrechnungsmonat
三者冲突导致抛出IllegalStateException。即使手动定义了getter,Lombok的@Data包含@Getter注解,加上Jackson的自动字段检测机制,依然会触发冲突。
解决方案
方案1:使用@JsonAlias指定反序列化别名(推荐)
@JsonAlias专门用于定义反序列化时可匹配的别名,序列化时仍使用字段名输出,无需手动编写@JsonGetter/@JsonSetter,避免冲突:
@JsonFormat(pattern="yyyy-MM") @JsonDeserialize(using = YearMonthDeserializer.class) @JsonAlias("abrechnungsMonat") // 反序列化接受该别名 private YearMonth abrechnungsmonat;
方案2:使用@JsonProperty统一配置
通过@JsonProperty同时控制序列化和反序列化的属性名,结合access参数明确读写规则:
@JsonFormat(pattern="yyyy-MM") @JsonDeserialize(using = YearMonthDeserializer.class) @JsonProperty(value = "abrechnungsmonat", access = JsonProperty.Access.READ_WRITE) @JsonProperty("abrechnungsMonat") // 反序列化匹配该名称 private YearMonth abrechnungsmonat;
方案3:禁用Jackson字段自动检测
在类上添加@JsonAutoDetect,关闭字段的自动识别,仅通过getter/setter处理属性:
@NoArgsConstructor @AllArgsConstructor @Data @ToString(callSuper = true) @SuperBuilder @JsonIgnoreProperties(ignoreUnknown = true) @JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.NONE) // 关闭字段自动检测 public class AusgangsrechnungGeneral extends Rechnung { // 原有代码不变 }
内容的提问来源于stack exchange,提问作者Tobias Walter

