问题描述
使用 Jackson 和 jackson-dataformat-xml 2.4.4,我试图反序列化一个 XML 文档,其中用 @XmlWrapperElement 注释的集合可能有零个元素,但 XML 包含空格(在我的情况下是换行符).Jackson 对此内容抛出 JsonMappingException 并显示消息无法从 VALUE_STRING 令牌中反序列化 java.util.ArrayList 的实例".我无法更改生成 XML 的方式.
Using Jackson and jackson-dataformat-xml 2.4.4, I'm trying to deserialize a XML document where a collection annotated with @XmlWrapperElement may have zero elements, but where the XML contains whitespace (in my case a line break). Jackson throws a JsonMappingException on this content with the message "Can not deserialize instance of java.util.ArrayList out of VALUE_STRING token". I cannot change the way the XML is produced.
示例:
static class Outer {
@XmlElementWrapper
List<Inner> inners;
}
static class Inner {
@XmlValue
String foo;
}
ObjectMapper mapper = new XmlMapper().registerModules(new JaxbAnnotationModule());
String xml = "<outer><inners>
</inners></outer>";
Outer outer = mapper.readValue(xml, Outer.class);
以下解决方法不起作用:
The following workarounds do not work:
- 启用
DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY
:在这种情况下,Jackson 想要使用空格作为内容实例化Inner
的虚假实例. - 为该字段为字符串和集合类型创建设置器.在这种情况下,我得到一个 JsonMappingException(冲突的属性内部"的 setter 定义").
- 在类似的 Stackoverflow 问题中,建议将 Jackson 降级到 2.2.3.这不能解决我的问题.
- Enabling
DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY
: In this case Jackson wants to instantiate a bogus instance ofInner
using the whitespace as content. - Creating setters for this field for both String and the collection type. In this case I get a JsonMappingException ("Conflicting setter definitions for property "inners"").
- In a similar Stackoverflow question it is suggested to downgrade Jackson to 2.2.3. This does not fix the problem for me.
有什么建议吗?
我可以通过包装 CollectionDeserializer 并检查空白标记来解决这个问题.然而,这对我来说看起来非常脆弱,例如我不得不重写另一个方法来重新包装对象.我可以发布解决方法,但更简洁的方法会更好.
I can work around this issue by wrapping the CollectionDeserializer and checking for a whitespace token. This looks however very fragile to me, e.g. I had to override another method to rewrap the object. I can post the workaround, but a cleaner approach would be better.
推荐答案
此问题的解决方法是包装标准 CollectionDeserializer
以返回包含空格的标记的空集合并注册新的 Deserializer.我把代码放到一个Module
中,这样就可以很容易地注册了:
A workaround for this problem is to wrap the standard CollectionDeserializer
to return an empty collection for tokens containing whitespace and register the new Deserializer. I put the code into a Module
so it can be registered easily:
import java.io.IOException;
import java.util.Collection;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.DeserializationConfig;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.deser.BeanDeserializerModifier;
import com.fasterxml.jackson.databind.deser.std.CollectionDeserializer;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.type.CollectionType;
public class XmlWhitespaceModule extends SimpleModule {
private static class CustomizedCollectionDeserialiser extends CollectionDeserializer {
public CustomizedCollectionDeserialiser(CollectionDeserializer src) {
super(src);
}
private static final long serialVersionUID = 1L;
@SuppressWarnings("unchecked")
@Override
public Collection<Object> deserialize(JsonParser jp, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
if (jp.getCurrentToken() == JsonToken.VALUE_STRING
&& jp.getText().matches("^[\r\n\t ]+$")) {
return (Collection<Object>) _valueInstantiator.createUsingDefault(ctxt);
}
return super.deserialize(jp, ctxt);
}
@Override
public CollectionDeserializer createContextual(DeserializationContext ctxt,
BeanProperty property) throws JsonMappingException {
return new CustomizedCollectionDeserialiser(super.createContextual(ctxt, property));
}
}
private static final long serialVersionUID = 1L;
@Override
public void setupModule(SetupContext context) {
super.setupModule(context);
context.addBeanDeserializerModifier(new BeanDeserializerModifier() {
@Override
public JsonDeserializer<?> modifyCollectionDeserializer(
DeserializationConfig config, CollectionType type,
BeanDescription beanDesc, JsonDeserializer<?> deserializer) {
if (deserializer instanceof CollectionDeserializer) {
return new CustomizedCollectionDeserialiser(
(CollectionDeserializer) deserializer);
} else {
return super.modifyCollectionDeserializer(config, type, beanDesc,
deserializer);
}
}
});
}
}
之后你可以像这样将它添加到你的ObjectMapper
:
After that you can add it to your ObjectMapper
like this:
ObjectMapper mapper = new XmlMapper().registerModule(new XmlWhitespaceModule());
这篇关于Jackson:忽略空 @XmlWrapperElement 集合中的空格的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!