新的Jackson-API为我们提供了方便的XML绑定(例如,就像JAXB ),但是我找不到任何方法来使Jackson序列化典型的"xsi:nil"-Attribute,它是用XML表示空值的事实标准?如果我看错了,请纠正我;-)
在JAXB中,这可以通过使用@XMLElement(nillable=true)注释java变量来轻松完成
另请参阅:http://blog.bdoughan.com/2012/04/binding-to-json-xml-handling-null.html
杰克逊能做到吗?
关于Jackson-XML,请参阅:https://github.com/FasterXML/jackson-dataformat-xml
发布于 2014-02-10 01:30:49
这并没有回答这个问题,但是提供了一个变通方法(非常麻烦)!
我设法为jackson编写了一些自定义的序列化程序/反序列化程序(直到jackson官方支持xsi:nil),它们允许以下内容:
如果在POJO
中将它们定义为xsi:nil元素,则它们对于POJO为NULL
使用此代码,可以提供与其他xml绑定库(JAXB..)的互操作性。这只能与空值的xsi:nil一起使用。
类项目:
public class Item {
public String x;
public Integer y;
public Integer z;
}类Main:
public class Main {
public static void main(String[] args) throws JsonParseException, JsonMappingException, IOException {
NumberDeserializers numberDeserializers = new NumberDeserializers();
XmlMapper xmlMapper = new XmlMapper();
xmlMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
// create custom-serialization
XmlSerializerProvider provider = new XmlSerializerProvider(new XmlRootNameLookup());
provider.setNullValueSerializer(new MyNullSerializer());
xmlMapper.setSerializerProvider(provider);
// create custom deserialization
SimpleModule myModule = new SimpleModule("Module", new Version(1, 9, 10, "FINAL"));
myModule.addDeserializer(String.class, new NullableDeserializer(new StringDeserializer()));
myModule.addDeserializer(Number.class, new NullableDeserializer(numberDeserializers.find(Integer.class, Integer.class.getName())));
myModule.addDeserializer(Float.class, new NullableDeserializer(numberDeserializers.find(Float.class, Float.class.getName())));
xmlMapper.registerModule(myModule);
// deserialize
Item value = xmlMapper.readValue(
"<item xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" ><a></a><x xsi:nil=\"true\"></x><y/><z>13</z></item>",
Item.class);
// serialize
String xml = xmlMapper.writeValueAsString(value);
System.out.println(xml);
}
}MyNullSerializer类:
public class MyNullSerializer extends JsonSerializer<Object> {
@Override
public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {
ToXmlGenerator xGen = (ToXmlGenerator) jgen;
xGen.writeStartObject();
try {
xGen.getStaxWriter().writeAttribute("xsi:nil", "true");
} catch (Exception e){
e.printStackTrace();
}
xGen.writeEndObject();
}
}MyNullDeserializer类:
public class MyNullDeserializer extends JsonDeserializer {
private JsonDeserializer delegate;
public MyNullDeserializer(JsonDeserializer delegate){
this.delegate = delegate;
}
@Override
public Object deserialize(JsonParser jp, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
FromXmlParser fxp = (FromXmlParser) jp;
boolean isNil = false;
XMLStreamReader reader = fxp.getStaxReader();
if (reader.isStartElement()){
if (reader.getAttributeCount() > 0){
String atVal = reader.getAttributeValue("http://www.w3.org/2001/XMLSchema-instance", "nil");
if (atVal != null){
if (Boolean.parseBoolean(atVal) == true){
isNil = true;
}
}
}
}
Object value = null;
if (isNil == false){
value = delegate.deserialize(jp, ctxt);
} else {
jp.getValueAsString(); // move forward
}
return value;
}
}发布于 2021-03-18 14:15:40
我对rnd的工作进行了扩展,因为它为所有字段启用了该功能,而不仅仅是其中的一部分。
这是一个您将添加到绑定中的模块,如下所示:
XmlMapper mapper = new XmlMapper();
XmlSerializerProvider provider = new XmlSerializerProvider(new XmlRootNameLookup());
provider.setNullValueSerializer(new NullSerializer());
mapper.setSerializerProvider(provider);
mapper.registerModule(new NullPointerModule());NullPointerModule实现了自己的自定义序列化程序,以传递当前字段自检所需的属性。
NullPointerModule.java:
public class NullPointerModule extends SimpleModule implements java.io.Serializable {
private static final long serialVersionUID = 1L;
@Override
public void setupModule(SetupContext context) {
// Need to modify BeanDeserializer, BeanSerializer that are used
context.addBeanSerializerModifier(new XmlBeanSerializerModifier() {
@Override
public List<BeanPropertyWriter> changeProperties(SerializationConfig config, BeanDescription beanDesc, List<BeanPropertyWriter> beanProperties) {
for (int i = 0, len = beanProperties.size(); i < len; ++i) {
BeanPropertyWriter bpw = beanProperties.get(i);
if (bpw.getClass().equals(BeanPropertyWriter.class)) {
beanProperties.set(i, new NullCheckedBeanPropertyWriter(bpw));
}
}
return beanProperties;
}
});
super.setupModule(context);
}
}接下来是实际的NullSerializer,它接受属性编写器并确定字段是否需要nil字段。
NullSerializer.java:
public class NullSerializer extends JsonSerializer<Object> {
@SuppressWarnings("unused")
public void serializeWithProperty(BeanPropertyWriter propertyWriter, Object value, JsonGenerator jgen, SerializerProvider provider) {
ToXmlGenerator xGen = (ToXmlGenerator) jgen;
XmlElement annotation = null;
if (propertyWriter != null) {
AnnotatedMember member = propertyWriter.getMember();
annotation = member.getAnnotation(XmlElement.class);
}
try {
if (annotation != null) {
if (annotation.nillable()) {
xGen.writeStartObject();
XMLStreamWriter staxWriter = xGen.getStaxWriter();
staxWriter.writeAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
staxWriter.writeAttribute("xsi:nil", "true");
xGen.writeEndObject();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
serializeWithProperty(null, value, jgen, provider);
}
}最后是propertyWriters的覆盖。这是一个小技巧,因为如果属性编写器本身被另一个模块中的另一个类替换,这可能会失败。
NullCheckedBeanPropertyWriter.java:
public class NullCheckedBeanPropertyWriter extends BeanPropertyWriter {
public NullCheckedBeanPropertyWriter(BeanPropertyWriter base) {
super(base);
}
@Override
public void serializeAsField(Object bean, JsonGenerator gen, SerializerProvider prov) throws Exception {
final Object value = (_accessorMethod == null) ? _field.get(bean)
: _accessorMethod.invoke(bean);
// Null handling is bit different, check that first
if (value == null) {
if (_nullSerializer != null) {
gen.writeFieldName(_name);
if (_nullSerializer instanceof NullSerializer) {
NullSerializer nullSerializer = (NullSerializer) _nullSerializer;
nullSerializer.serializeWithProperty(this, bean, gen, prov);
return;
}
_nullSerializer.serialize(null, gen, prov);
}
return;
}
super.serializeAsField(bean, gen, prov);
}
}然后可以使用@XmlElement(nillable=true)添加这些字段,使其符合您的需要。
https://stackoverflow.com/questions/21002930
复制相似问题