Java 带Jackson的动态根元素
我目前正在从事一个项目,该项目处理的元素(出于遗留原因)必须具有表示其类型的标记名 基本上我有:Java 带Jackson的动态根元素,java,xml,jackson,xml-serialization,jackson-dataformat-xml,Java,Xml,Jackson,Xml Serialization,Jackson Dataformat Xml,我目前正在从事一个项目,该项目处理的元素(出于遗留原因)必须具有表示其类型的标记名 基本上我有: @JsonRootName(“节点”) 类节点文档{ 私有字符串类型; } 其输出类似于: 但我们所期望的是: @JsonRootName在方法或属性上似乎不可用 即使有SerializationConfig.WithRoName()或自定义序列化程序,我似乎也找不到用存储在对象本身中的动态值定义根名称的方法。我假设NodeDocument包含不止一个属性。在这种情况下,您需要与BeanS
@JsonRootName(“节点”)
类节点文档{
私有字符串类型;
}
其输出类似于:
但我们所期望的是:
@JsonRootName
在方法或属性上似乎不可用
即使有
SerializationConfig.WithRoName()
或自定义序列化程序,我似乎也找不到用存储在对象本身中的动态值定义根名称的方法。我假设NodeDocument
包含不止一个属性。在这种情况下,您需要与BeanSerializerModifier
一起实现自定义serialiser,它允许您序列化所有属性。下面的代码显示了完整的解决方案:
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
}
import com.fasterxml.jackson.annotation.JsonIgnore;
导入com.fasterxml.jackson.core.JsonGenerator;
导入com.fasterxml.jackson.databind.BeanDescription;
导入com.fasterxml.jackson.databind.JsonSerializer;
导入com.fasterxml.jackson.databind.SerializationConfig;
导入com.fasterxml.jackson.databind.SerializationFeature;
导入com.fasterxml.jackson.databind.SerializerProvider;
导入com.fasterxml.jackson.databind.module.SimpleModule;
导入com.fasterxml.jackson.databind.ser.BeanSerializerModifier;
导入com.fasterxml.jackson.databind.util.NameTransformer;
导入com.fasterxml.jackson.dataformat.xml.XmlMapper;
导入com.fasterxml.jackson.dataformat.xml.ser.ToXmlGenerator;
导入javax.xml.namespace.QName;
导入java.io.IOException;
导入java.util.Objects;
公共类XmlJacksonApp{
公共静态void main(字符串…参数)引发异常{
SimpleModule dynamicRootNameModule=新SimpleModule();
dynamicRootNameModule.setSerializerModifier(新的DynamicRootNameBeanSerializerModifier());
XmlMapper mapper=XmlMapper.xmlBuilder()
.enable(SerializationFeature.INDENT_输出)
.addModule(dynamicRootNameModule)
.build();
NodeDocument元素=新的NodeDocument();
元素setId(123);
元素集合名(“Rick and Morty.doc”);
元素集类型(“情景喜剧”);
mapper.writeValue(System.out,element);
}
}
类DynamicRootNameBeanSerializerModifier扩展了BeanSerializerModifier{
@凌驾
公共JsonSerializer修改序列化程序(SerializationConfig配置、BeanDescription beanDesc、JsonSerializer序列化程序){
if(beanDesc.getBeanClass()==NodeDocument.class){
返回新的NodeDocumentJsonSerializer((JsonSerializer)序列化程序);
}
返回super.modifySerializer(config、beanDesc、serializer);
}
}
类NodeDocumentJsonSerializer扩展了JsonSerializer{
私有最终JsonSerializer序列化程序;
NodeDocumentJsonSerializer(JsonSerializer序列化程序){
this.serializer=Objects.requirennull(序列化程序);
}
@凌驾
public void serialize(NodeDocument值、JsonGenerator gen、SerializerProvider序列化程序)引发IOException{
ToXmlGenerator xmlGen=(ToXmlGenerator)gen;
writeDynamicRootName(value.getType(),xmlGen);
序列化属性(值、根、序列化器);
写入对象(xmlGen);
}
私有void writeDynamicRootName(字符串rootName,ToXmlGenerator xmlGen)引发IOException{
setNextName(新的QName(“,rootName));
xmlGen.writeStartObject();
}
私有void serializeProperties(NodeDocument值、JsonGenerator gen、SerializerProvider序列化程序)引发IOException{
反包装序列化程序(NameTransformer.NOP).serialize(value,gen,serializer);
}
私有void writeEndObject(ToXmlGenerator xmlGen)引发IOException{
xmlGen.writeEndObject();
}
}
类节点文档{
@杰索尼奥雷
私有字符串类型;
私有int-id;
私有字符串名称;
//能手,二传手
}
以上代码打印:
<sitcom>
<id>123</id>
<name>Rick and Morty.doc</name>
</sitcom>
123
瑞克和莫蒂
假设您可以轻松地切换/配置映射器一个脏的、不太可配置但仍然非常简单的方法是覆盖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;
}
}
无论如何都不是一个完美的解决方案,也可能不适用于所有情况,但作为一个选项的示例,可根据情况进行更改。请查看以下答案:。您需要使用
ToXmlGenerator
类和setNextName
方法实现自定义序列化程序并从给定实例设置根名称;我不知道setNextName
,但是有没有什么工具可以避免序列化对象属性所需的所有样板代码?