我试图写一些代码,将JSON反序列化成别人的类。也就是说,我不拥有目标类,所以我不能注释它。
特别是,这个类有一些使反序列化过程复杂化的辅助方法。像这样:class Result {
private List<String> ids;
public List<String> getIds() {
return ids;
}
public void setIds(List<String> ids) {
this.ids = ids;
}
// Helpers
public String getId() {
return this.ids.isEmpty() ? null : this.ids.get(0);
}
public void setId(String id) {
this.ids = List.of(id);
}
}
当序列化时,我们得到ids
和id
作为字段:
{
"ids": ["1", "2", "3"],
"id": "1"
}
然后当反序列化这个JSON时,Jackson调用了两个setter——这很合理——因此对象是错误的。最终的结果是ids
字段被设置为["1"]
和,而不是["1", "2", "3"]
,因为它应该是。
我想要做的就是修复这个。我认为最简单/最安全/最好的方法是能够在反序列化过程的某个地方修改JSON AST。具体来说就是去掉"id"字段,这样它就不会被标准的反序列化器看到。(我知道这可以通过手动执行字符串操作来实现,但这很糟糕)
我可以为所有字段编写一个完整的反序列化器,但是如果将来添加任何新字段,当我真正想做的是忽略单个字段并将其他所有内容正常处理时,我就有义务维护它。真正的类目前实际上有十几个字段,我不能保证将来不会改变。
我想不出来的是怎么做这件事。我真的希望有一些标准的JsonDeserializer
子类,让我这样做,但我找不到一个。我所能解决的最好的问题是一个正常的StdDeserializer
,然后使用parser.getCodec().treeToValue()
——感谢这个答案——除了这会导致一个无限循环,因为它每次都调用完全相同的反序列化器!令人沮丧的是,这个问题的大多数答案都是"只需注释类";——这在这里是行不通的!
是否有一个标准的方法来实现这一点?
欢呼在这种情况下有Jacksons mixins,这是一个非常有用的功能!
对于你的例子,定义mixin类并像注释原始类一样注释它;您只需要包含覆盖,例如:
@JsonIgnoreProperties({ "id" })
public class ResultMixin {
// nothing else required!
}
现在,您必须挂接ObjectMapper
创建来定义mixin。这取决于你使用的框架,但最终应该是这样的:
ObjectMapper om = ...
om.addMixIn(Result.class, ResultMixin.class);
现在,这个ObjectMapper
将考虑来自您的mixin的信息来序列化类型为Result
的对象(并忽略合成的id
属性)。
当然,我已经知道怎么做了:)
我可以用BeanDeserializerModifier
代替,使事情按照需要行事。
public class MyDeserializerModifier extends BeanDeserializerModifier {
@Override
public List<BeanPropertyDefinition> updateProperties(final DeserializationConfig config,
final BeanDescription beanDesc, final List<BeanPropertyDefinition> propDefs) {
if (beanDesc.getBeanClass().equals(Result.class)) {
propDefs.removeIf(prop -> prop.getName().equals("id"));
}
return super.updateProperties(config, beanDesc, propDefs);
}
@Override
public BeanDeserializerBuilder updateBuilder(final DeserializationConfig config, final BeanDescription beanDesc,
final BeanDeserializerBuilder builder) {
if (beanDesc.getBeanClass().equals(Result.class)) {
builder.addIgnorable("id");
}
return super.updateBuilder(config, beanDesc, builder);
}
}