英文:
How to ignore a list entry causing a deserialization error in Jackson?
问题
我正试图使用Jackson对JSON结构进行反序列化,我正在使用一个类似这样的DTO:
public class RootLevelDTO {
private List<ComplexEntry> complexEntries;
// ... 其他字段,与问题无关
}
现在,ComplexEntry
可能有子类型,这些子类型具有枚举类型的属性等。如果通信的另一侧更新了他们的API,例如添加了另一个子类型或添加了枚举字面量,很多问题可能会出现。
我想做的是告诉Jackson:
- 如果在反序列化
complexEntries
字段时遇到任何数据绑定错误... - ... 不要抛出异常,而是忽略这个条目并继续处理下一个。
到目前为止,我尝试过为 ComplexEntry
使用一个委托反序列化器:
public class ComplexEntryDeserializer extends StdDeserializer<ComplexEntry> {
private StdDeserializer<ComplexEntry> delegate;
public ComplexEntryDeserializer(StdDeserializer<ComplexEntry> delegate){
this.delegate = delegate;
}
public ComplexEntry deserialize(JsonParser p, DeserializationContext ctxt){
try {
return this.delegate.deserialize(p, ctxt);
}catch(Exception e){
// 列表条目无法反序列化,但是我们必须在这里返回*一些内容*
return null;
}
}
// ... 其他必需的方法,与此无关
}
这个解决方案的问题是它会向 complexEntries
列表引入 null
值,然后我必须使用 Converter
显式地摆脱它们。
有没有更优雅的解决方案来解决这个问题?
英文:
I'm trying to deserialize a JSON structure with Jackson and I'm working with a DTO that looks like this:
public class RootLevelDTO {
private List<ComplexEntry> complexEntries;
// ... other fields, not relevant
}
Now, the ComplexEntry
can have sub-types, those have properties of enum types etc. A lot can go wrong here if the other side of the communication updates their API and e.g. adds another sub type or adds an enum literal.
What I would like to do is to tell Jackson:
- if you encounter any databinding error during deserialization of the
complexEntries
field... - ... do not throw an exception, but instead ignore this entry and continue with the next.
What I tried so far is to use a delegating deserializer for ComplexEntry
:
public class ComplexEntryDeserializer extends StdDeserializer<ComplexEntry> {
private StdDeserializer<ComplexEntry> delegate;
public ComplexEntryDeserializer(StdDeserializer<ComplexEntry> delegate){
this.delegate = delegate;
}
public ComplexEntry deserialize(JsonParser p, DeserializationContext ctxt){
try {
return this.delegate.deserialize(p, ctxt);
}catch(Exception e){
// the list entry failed to deserialize, but we have to return *something* here
return null;
}
}
// ... other mandatory methods, not relevant here
}
This solution has the problem that it will introduce null
values to the complexEntries
list, which I then have to explicitly get rid of with a Converter
.
Is there a more elegant solution to this problem?
答案1
得分: 2
以下是翻译好的部分:
"After a lot of tinkering I've ended up with the following solution. It doesn't require any additional jackson modules or other magic, only a single (specific) deserializer.
DTO(数据传输对象):
public class RootLevelDTO {
// use a custom deserializer for the list
@JsonDeserialize(using = ListOfComplexEntryDeserializer.class)
private List<ComplexEntry> complexEntries;
}
Deserializer(反序列化器):
public class ListOfComplexEntryDeserializer extends JsonDeserializer<List<ComplexEntry>> {
@Override
public List<ComplexEntry> deserialize(JsonParser p, DeserializationContext ctxt) {
List<ComplexEntry> resultList = new ArrayList<>();
while(p.nextToken() != JsonToken.END_ARRAY){
try {
// delegate the deserialization of the individual list entries to the standard deserializers
resultList.add(ctxt.readValue(p, ComplexEntry.class))
}catch(Exception e){
// log that the entry wasn't deserialized properly
System.out.println("ComplexEntry could not be read and will be ignored.");
}
}
return resultList;
}
}
Big disclaimer: While the code above works, it's not something you should go for by design. I'm really with my back to the wall here and have no other choice (due to external factors beyond my control), and for that case it works."
英文:
After a lot of tinkering I've ended up with the following solution. It doesn't require any additional jackson modules or other magic, only a single (specific) deserializer.
DTO:
public class RootLevelDTO {
// use a custom deserializer for the list
@JsonDeserialize(using = ListOfComplexEntryDeserializer.class)
private List<ComplexEntry> complexEntries;
}
Deserializer:
public class ListOfComplexEntryDeserializer extends JsonDeserializer<List<ComplexEntry>> {
@Override
public List<ComplexEntry> deserialize(JsonParser p, DeserializationContext ctxt) {
List<ComplexEntry> resultList = new ArrayList<>();
while(p.nextToken() != JsonToken.END_ARRAY){
try {
// delegate the deserialization of the individual list entries to the standard deserializers
resultList.add(ctxt.readValue(p, ComplexEntry.class))
}catch(Exception e){
// log that the entry wasn't deserialized properly
System.out.println("ComplexEntry could not be read and will be ignored.");
}
}
return resultList;
}
}
Big disclaimer: While the code above works, it's not something you should go for by design. I'm really with my back to the wall here and have no other choice (due to external factors beyond my control), and for that case it works.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论