[英]Dynamic root element with Jackson
我目前正在處理一個項目,該項目處理(出於遺留原因)必須具有代表其類型的標簽名稱的元素。
基本上我有這個:
@JsonRootName("node")
class NodeDocument {
private String type;
}
輸出如下:
<node type="someType"></node>
但預期的是:
<someType></someType>
@JsonRootName
似乎不適用於方法或屬性。
即使有SerializationConfig.withRooName()
或自定義序列化程序,我似乎也無法找到一種方法來使用存儲在 object 本身中的動態值來定義根名稱。
我假設NodeDocument
包含不止一個屬性。 在這種情況下,您需要與允許您序列化所有屬性的BeanSerializerModifier
一起實現自定義序列化器。 下面的代碼顯示了完整的解決方案:
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializationConfig;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.BeanSerializerModifier;
import com.fasterxml.jackson.databind.util.NameTransformer;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.dataformat.xml.ser.ToXmlGenerator;
import javax.xml.namespace.QName;
import java.io.IOException;
import java.util.Objects;
public class XmlJacksonApp {
public static void main(String... args) throws Exception {
SimpleModule dynamicRootNameModule = new SimpleModule();
dynamicRootNameModule.setSerializerModifier(new DynamicRootNameBeanSerializerModifier());
XmlMapper mapper = XmlMapper.xmlBuilder()
.enable(SerializationFeature.INDENT_OUTPUT)
.addModule(dynamicRootNameModule)
.build();
NodeDocument element = new NodeDocument();
element.setId(123);
element.setName("Rick and Morty.doc");
element.setType("sitcom");
mapper.writeValue(System.out, element);
}
}
class DynamicRootNameBeanSerializerModifier extends BeanSerializerModifier {
@Override
public JsonSerializer<?> modifySerializer(SerializationConfig config, BeanDescription beanDesc, JsonSerializer<?> serializer) {
if (beanDesc.getBeanClass() == NodeDocument.class) {
return new NodeDocumentJsonSerializer((JsonSerializer<NodeDocument>) serializer);
}
return super.modifySerializer(config, beanDesc, serializer);
}
}
class NodeDocumentJsonSerializer extends JsonSerializer<NodeDocument> {
private final JsonSerializer<NodeDocument> serializer;
NodeDocumentJsonSerializer(JsonSerializer<NodeDocument> serializer) {
this.serializer = Objects.requireNonNull(serializer);
}
@Override
public void serialize(NodeDocument value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
ToXmlGenerator xmlGen = (ToXmlGenerator) gen;
writeDynamicRootName(value.getType(), xmlGen);
serializeProperties(value, gen, serializers);
writeEndObject(xmlGen);
}
private void writeDynamicRootName(String rootName, ToXmlGenerator xmlGen) throws IOException {
xmlGen.setNextName(new QName("", rootName));
xmlGen.writeStartObject();
}
private void serializeProperties(NodeDocument value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
serializer.unwrappingSerializer(NameTransformer.NOP).serialize(value, gen, serializers);
}
private void writeEndObject(ToXmlGenerator xmlGen) throws IOException {
xmlGen.writeEndObject();
}
}
class NodeDocument {
@JsonIgnore
private String type;
private int id;
private String name;
// getters, setters
}
上面的代碼打印:
<sitcom>
<id>123</id>
<name>Rick and Morty.doc</name>
</sitcom>
假設您可以輕松地切換/配置映射器一個臟的並且不是那么可配置但仍然很簡單的方法是覆蓋XmlMapper
,例如:
@SuppressWarnings("serial")
public class MyXmlMapper extends XmlMapper {
@Override
public String writeValueAsString(Object value) throws JsonProcessingException {
String xml = super.writeValueAsString(value);
if(value instanceof NodeDocument) {
return xml.replaceAll("NodeDocument", ((NodeDocument)value).getType());
}
return xml;
}
}
無論如何都不是一個完美的解決方案,並且可能不適合所有情況,但作為一個選項的示例,可以根據情況進行更改。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.