解决Jackson中属性的Getter定义冲突问题
解决Jackson Getter冲突与多类型JSON字段映射问题
问题场景
你编写的Java类如下:
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import lombok.Getter; import lombok.Setter; import java.util.List; @Getter @Setter @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL) public class Options { @JsonProperty("value") private String value; @JsonProperty("value") private Value valueObj; }
使用Jackson处理JSON时出现错误:
Exception in thread "main" com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Conflicting getter definitions for property "value": Options#getValue() vs Options#getValueObj()
需要复用Options类映射的JSON数据如下:
{ "behaviors": [ { "name": "dnsAsyncRefresh", "options": { "enabled": true, "timeout": "1h", "value": { "id": "1234" } } }, { "name": "timeout", "options": { "value": "5s" } } ] }
错误原因
你给两个不同字段都标记了@JsonProperty("value"),Lombok自动生成的getValue()和getValueObj()方法会被Jackson同时识别为JSON字段value的getter,导致属性映射冲突。
解决方案
方案1:用Object类型统一接收多类型value
将两个value相关字段合并为一个Object类型的字段,Jackson会自动根据JSON中的实际类型(字符串或对象)填充该字段,同时避免getter冲突。
修改后的Options类:
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import lombok.Getter; import lombok.Setter; @Getter @Setter @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL) public class Options { private Boolean enabled; private String timeout; @JsonProperty("value") private Object value; // 辅助方法:快速获取String类型的value public String getValueAsString() { return (value instanceof String) ? (String) value : null; } // 辅助方法:快速获取Value对象类型的value public Value getValueAsValueObj() { return (value instanceof Value) ? (Value) value : null; } }
对应的Value类:
import lombok.Getter; import lombok.Setter; @Getter @Setter public class Value { private String id; }
方案2:自定义反序列化器(类型更严谨)
如果需要对类型转换做更严格的控制,可以自定义反序列化器,根据JSON节点的类型决定反序列化为String还是Value对象。
第一步:编写自定义反序列化器
import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.JsonNode; import java.io.IOException; public class ValueDeserializer extends JsonDeserializer<Object> { @Override public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { JsonNode node = p.getCodec().readTree(p); if (node.isTextual()) { return node.asText(); } else if (node.isObject()) { return p.getCodec().treeToValue(node, Value.class); } return null; } }
第二步:在Options类中应用该反序列化器
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import lombok.Getter; import lombok.Setter; @Getter @Setter @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL) public class Options { private Boolean enabled; private String timeout; @JsonProperty("value") @JsonDeserialize(using = ValueDeserializer.class) private Object value; // 同样可以添加辅助方法便捷取值 public String getValueAsString() { return (value instanceof String) ? (String) value : null; } public Value getValueAsValueObj() { return (value instanceof Value) ? (Value) value : null; } }
内容的提问来源于stack exchange,提问作者Lizzie
相关产品推荐
相关产品推荐

