json - 如何将单个 json 属性反序列化为多个 Java 字段(如果可能使用转换器)
问题描述
有这个类:
@Getter
@Setter
public class Result {
private String positionText;
private Integer positionNumber;
.. many many other properties ..
}
并反序列化这个json:
[
{
"position": "1",
.. many many other properties ..
},
{
"position": "FOO",
.. many many other properties ..
},
..
}
position
json 属性如何反序列化为positionText
和positionNumber
Java 字段?
public abstract class ResultMixIn {
@JsonProperty("position")
abstract String getPositionText();
@JsonProperty("position")
abstract Integer getPositionNumber();
}
但这给出了一个:
Conflicting getter definitions for property "position": com.example.domain.Result#getPositionText() vs com.example.domain.Result#getPositionNumber()
同样将抽象 getter 更改为 setter 也没有什么不同。
如果可能的话,我想避免完全成熟的ResultDeserializer
扩展StdDeserializer
,因为Result
该类具有更多我不希望“手动”反序列化的属性。
PS:我不关心序列化。我只是反序列化模型。
解决方案
首先,您需要注释Result
类的属性,以便杰克逊将反序列化该positionText
属性,而不是positionNumber
. 您将在泰勒制造的反序列化器中自己完成后者。
@Getter
@Setter
public class Result {
@JsonProperty("position")
private String positionText;
@JsonIgnore
private Integer positionNumber;
.. many many other properties ..
}
默认情况下,Jackson 将使用 aBeanDeserializer
来反序列Result
化对象。但是你想要这个反序列化器的一个稍微修改的实现。
这个答案的其余部分很大程度上是对问题的接受答案的改编,我如何从 Jackson 的自定义反序列化器中调用默认反序列化器。
像往常一样,您的反序列化器从 扩展StdDeserializer<Result>
,但它也实现了 ResolvableDeserializer
接口。在该deserialize
方法中,大部分工作都委托给BeanDeserializer
我们从 Jackson 获得的默认反序列化器(在本例中为 a )。我们只添加了一个小的额外逻辑,用于根据属性设置positionNumber
属性positionText
。
public class ResultDeserializer extends StdDeserializer<Result> implements ResolvableDeserializer {
private final JsonDeserializer<?> defaultDeserializer;
public ResultDeserializer(JsonDeserializer<?> defaultDeserializer) {
super(Result.class);
this.defaultDeserializer = defaultDeserializer;
}
@Override
public void resolve(DeserializationContext ctxt) throws JsonMappingException {
if (defaultDeserializer instanceof ResolvableDeserializer) {
// We need to resolve the default deserializer, or else it won't work properly.
((ResolvableDeserializer) defaultDeserializer).resolve(ctxt);
}
}
@Override
public Result deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
// let defaultDeserializer do the work:
Result result = (Result) defaultDeserializer.deserialize(p, ctxt);
// here you do your custom logic:
String positionText = result.getPositionText();
if (positionText != null) {
try {
result.setPositionNumber(Integer.valueOf(positionText));
} catch(NumberFormatException e) {
// positionText is not a valid integer
}
}
return result;
}
}
最后,您需要告诉 Jackson 您希望将上述内容ResultDeserializer
用于反序列Result
化对象。这是通过以下自定义的 来完成的ObjectMapper
,它将包裹ResultDeserializer
在 Jackson 的默认反序列化器周围,仅当Result
要反序列化对象时:
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new SimpleModule()
.setDeserializerModifier(new BeanDeserializerModifier() {
@Override
public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config,
BeanDescription beanDesc, JsonDeserializer<?> deserializer) {
if (Result.class == beanDesc.getBeanClass())
return new ResultDeserializer(deserializer); // your deserializer
return deserializer;
}
}));
然后你可以像往常一样反序列化你的 JSON 内容,例如:
File file = new File("example.json");
List<Result> results = objectMapper.readValue(file, new TypeReference<List<Result>>() {});
推荐阅读
- python-3.x - 单元测试初始化类而不调用参数,如何将参数放入类中?
- c# - C# wpf 打开新窗口表单列表组合框
- python - 在numpy std计算中,np.std(y_test == y_test_predict),比较测试分割和预测结果是什么意思
- excel - 防止在子迭代时多次单击命令按钮
- database-design - BCNF关系设计中如何表示变长序列?
- sql - 为什么在此查询中我的总和列加倍?
- java - 添加重新打包目标会导致“创建名称为 'entityManagerFactory' 的 bean 时出错”
- laravel - Laravel Passport invalid_grant 用于密码 grant_type
- combobox - Excel:如果 ComboBox 1 为空,则将组合框 3-8 .visible 设置为 false
- jakarta-ee - 当针对 Arquillian 自由管理运行测试时,OpenLiberty 启动冻结