使用Jackson和jackson-dataformat-xml 2.4.4,我试图反序列化一个XML文档,其中用@XmlWrapperElement注释的集合可能没有元素,但XML包含空格(在我的例子中是一行)打破)。 Jackson在此内容上抛出JsonMappingException,并显示消息“无法从VALUE_STRING标记中反序列化java.util.ArrayList的实例”。我无法改变XML的生成方式。
示例:
static class Outer {
@XmlElementWrapper
List<Inner> inners;
}
static class Inner {
@XmlValue
String foo;
}
ObjectMapper mapper = new XmlMapper().registerModules(new JaxbAnnotationModule());
String xml = "<outer><inners>\n</inners></outer>";
Outer outer = mapper.readValue(xml, Outer.class);
以下变通办法不起作用:
DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY
:在这种情况下,Jackson希望使用空格作为内容来实例化Inner
的虚假实例。有什么建议吗?
编辑:我可以通过包装CollectionDeserializer并检查空白标记来解决此问题。然而,这看起来非常脆弱,例如我不得不重写另一个方法来重新包装对象。我可以发布解决方法,但更清洁的方法会更好。
答案 0 :(得分:5)
此问题的解决方法是包装标准CollectionDeserializer
以返回包含空格的标记的空集合并注册新的反序列化程序。我将代码放入Module
,以便轻松注册:
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
,如下所示:
ObjectMapper mapper = new XmlMapper().registerModule(new XmlWhitespaceModule());