杰克逊根据字段值添加包装器
Jackson add wrapper based on field values
我有一个 class 如下所示:
@JsonRootName("ASSETS")
public class Assets{
String val1;
String val2;
}
不幸的是我需要将它序列化为这样的东西:
<ASSETS>
<ASSET>
<val1_val2>
<val1>x</val1>
<val2>y</val2>
</val1_val2>
</ASSET>
<ASSET>
<val1_val2>
<val1>x</val1>
<val2>y</val2>
</val1_val2>
</ASSET>
</ASSETS>
我可以做到在 ASSETS
中有 ASSET
个对象的列表,但是如何添加由两个字段组成的额外包装器?
您需要编写自定义序列化程序。为此,扩展 com.fasterxml.jackson.databind.JsonSerializer
class。此外,要创建额外的环绕元素,请使用 startWrappedValue 方法。示例代码如下所示:
import com.fasterxml.jackson.annotation.JsonRootName;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.ser.ToXmlGenerator;
import javax.xml.namespace.QName;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class XmlMapperApp {
public static void main(String[] args) throws Exception {
XmlMapper xmlMapper = new XmlMapper();
xmlMapper.enable(SerializationFeature.INDENT_OUTPUT);
xmlMapper.setDefaultUseWrapper(false);
Assets assets = new Assets();
assets.getAssets().add(new Asset());
assets.getAssets().add(new Asset());
System.out.println(xmlMapper.writeValueAsString(assets));
}
}
class AssetXMLSerializer extends JsonSerializer<Asset> {
private final QName wrapper = new QName("val1_val2");
@Override
public void serialize(Asset value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
ToXmlGenerator xmlGen = (ToXmlGenerator) gen;
xmlGen.writeStartObject();
xmlGen.startWrappedValue(wrapper, wrapper);
xmlGen.writeStringField("val1", value.getVal1());
xmlGen.writeStringField("val2", value.getVal2());
xmlGen.finishWrappedValue(wrapper, wrapper);
xmlGen.writeEndObject();
}
}
@JsonRootName("ASSETS")
class Assets {
@JacksonXmlProperty(localName = "ASSET")
private List<Asset> assets = new ArrayList<>();
// getters, setters, toString
}
@JsonSerialize(using = AssetXMLSerializer.class)
class Asset {
private String val1;
private String val2;
// getters, setters, toString
}
以上代码打印:
<ASSETS>
<ASSET>
<val1_val2>
<val1>x</val1>
<val2>y</val2>
</val1_val2>
</ASSET>
<ASSET>
<val1_val2>
<val1>x</val1>
<val2>y</val2>
</val1_val2>
</ASSET>
</ASSETS>
为一个巨大的 bean 使用默认序列化器的解决方案
要为 Asset
class 使用默认 bean 序列化程序,您需要使用 BeanSerializerModifier
并使用 SimpleModule
注册它。我们需要调用受保护的 serializeFields
方法,所以我创建了 ExpandXmlBeanSerializer
只是为了使它成为 public 以便我们可以在我们的实现中使用它:
import com.fasterxml.jackson.annotation.JsonRootName;
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.ser.std.BeanSerializerBase;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.ser.ToXmlGenerator;
import com.fasterxml.jackson.dataformat.xml.ser.XmlBeanSerializer;
import javax.xml.namespace.QName;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class XmlMapperApp {
public static void main(String[] args) throws Exception {
SimpleModule assetModule = new SimpleModule();
assetModule.setSerializerModifier(new LoopBackBeanSerializerModifier());
XmlMapper xmlMapper = new XmlMapper();
xmlMapper.registerModule(assetModule);
xmlMapper.enable(SerializationFeature.INDENT_OUTPUT);
xmlMapper.setDefaultUseWrapper(false);
Assets assets = new Assets();
assets.getAssets().add(new Asset("x0", "y0"));
assets.getAssets().add(new Asset("x1", "y1"));
System.out.println(xmlMapper.writeValueAsString(assets));
}
}
class LoopBackBeanSerializerModifier extends BeanSerializerModifier {
@Override
public JsonSerializer<?> modifySerializer(SerializationConfig config, BeanDescription beanDesc, JsonSerializer<?> serializer) {
if (beanDesc.getBeanClass() == Asset.class) {
return new AssetXMLSerializer(new ExpandXmlBeanSerializer((BeanSerializerBase) serializer));
}
return serializer;
}
}
class ExpandXmlBeanSerializer extends XmlBeanSerializer {
public ExpandXmlBeanSerializer(BeanSerializerBase src) {
super(src);
}
@Override
public void serializeFields(Object bean, JsonGenerator gen0, SerializerProvider provider) throws IOException {
super.serializeFields(bean, gen0, provider);
}
}
class AssetXMLSerializer extends JsonSerializer<Asset> {
private final QName wrapper;
private final ExpandXmlBeanSerializer baseSerializer;
public AssetXMLSerializer(ExpandXmlBeanSerializer baseSerializer) {
this.baseSerializer = Objects.requireNonNull(baseSerializer);
String fields = String.join("_",
Stream.of(Asset.class.getDeclaredFields())
.map(Field::getName)
.collect(Collectors.toList()));
this.wrapper = new QName(fields);
}
@Override
public void serialize(Asset value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
ToXmlGenerator xmlGen = (ToXmlGenerator) gen;
xmlGen.writeStartObject();
xmlGen.startWrappedValue(wrapper, wrapper);
baseSerializer.serializeFields(value, gen, serializers);
xmlGen.finishWrappedValue(wrapper, wrapper);
xmlGen.writeEndObject();
}
}
@JsonRootName("ASSETS")
class Assets {
@JacksonXmlProperty(localName = "ASSET")
private List<Asset> assets = new ArrayList<>();
// getters, setters, toString
}
class Asset {
private String val1;
private String val2;
public Asset(String val1, String val2) {
this.val1 = val1;
this.val2 = val2;
}
// getters, setters, toString
}
另请参阅:
- Jackson xml and json root element
- Multiple Jackson XML Custom (XMLStreamWriter) Serialisers throws Exception
SpringBoot: Consume & Produce XML with a Custom Serializer + Deserializer
我有一个 class 如下所示:
@JsonRootName("ASSETS")
public class Assets{
String val1;
String val2;
}
不幸的是我需要将它序列化为这样的东西:
<ASSETS>
<ASSET>
<val1_val2>
<val1>x</val1>
<val2>y</val2>
</val1_val2>
</ASSET>
<ASSET>
<val1_val2>
<val1>x</val1>
<val2>y</val2>
</val1_val2>
</ASSET>
</ASSETS>
我可以做到在 ASSETS
中有 ASSET
个对象的列表,但是如何添加由两个字段组成的额外包装器?
您需要编写自定义序列化程序。为此,扩展 com.fasterxml.jackson.databind.JsonSerializer
class。此外,要创建额外的环绕元素,请使用 startWrappedValue 方法。示例代码如下所示:
import com.fasterxml.jackson.annotation.JsonRootName;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.ser.ToXmlGenerator;
import javax.xml.namespace.QName;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class XmlMapperApp {
public static void main(String[] args) throws Exception {
XmlMapper xmlMapper = new XmlMapper();
xmlMapper.enable(SerializationFeature.INDENT_OUTPUT);
xmlMapper.setDefaultUseWrapper(false);
Assets assets = new Assets();
assets.getAssets().add(new Asset());
assets.getAssets().add(new Asset());
System.out.println(xmlMapper.writeValueAsString(assets));
}
}
class AssetXMLSerializer extends JsonSerializer<Asset> {
private final QName wrapper = new QName("val1_val2");
@Override
public void serialize(Asset value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
ToXmlGenerator xmlGen = (ToXmlGenerator) gen;
xmlGen.writeStartObject();
xmlGen.startWrappedValue(wrapper, wrapper);
xmlGen.writeStringField("val1", value.getVal1());
xmlGen.writeStringField("val2", value.getVal2());
xmlGen.finishWrappedValue(wrapper, wrapper);
xmlGen.writeEndObject();
}
}
@JsonRootName("ASSETS")
class Assets {
@JacksonXmlProperty(localName = "ASSET")
private List<Asset> assets = new ArrayList<>();
// getters, setters, toString
}
@JsonSerialize(using = AssetXMLSerializer.class)
class Asset {
private String val1;
private String val2;
// getters, setters, toString
}
以上代码打印:
<ASSETS>
<ASSET>
<val1_val2>
<val1>x</val1>
<val2>y</val2>
</val1_val2>
</ASSET>
<ASSET>
<val1_val2>
<val1>x</val1>
<val2>y</val2>
</val1_val2>
</ASSET>
</ASSETS>
为一个巨大的 bean 使用默认序列化器的解决方案
要为 Asset
class 使用默认 bean 序列化程序,您需要使用 BeanSerializerModifier
并使用 SimpleModule
注册它。我们需要调用受保护的 serializeFields
方法,所以我创建了 ExpandXmlBeanSerializer
只是为了使它成为 public 以便我们可以在我们的实现中使用它:
import com.fasterxml.jackson.annotation.JsonRootName;
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.ser.std.BeanSerializerBase;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.ser.ToXmlGenerator;
import com.fasterxml.jackson.dataformat.xml.ser.XmlBeanSerializer;
import javax.xml.namespace.QName;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class XmlMapperApp {
public static void main(String[] args) throws Exception {
SimpleModule assetModule = new SimpleModule();
assetModule.setSerializerModifier(new LoopBackBeanSerializerModifier());
XmlMapper xmlMapper = new XmlMapper();
xmlMapper.registerModule(assetModule);
xmlMapper.enable(SerializationFeature.INDENT_OUTPUT);
xmlMapper.setDefaultUseWrapper(false);
Assets assets = new Assets();
assets.getAssets().add(new Asset("x0", "y0"));
assets.getAssets().add(new Asset("x1", "y1"));
System.out.println(xmlMapper.writeValueAsString(assets));
}
}
class LoopBackBeanSerializerModifier extends BeanSerializerModifier {
@Override
public JsonSerializer<?> modifySerializer(SerializationConfig config, BeanDescription beanDesc, JsonSerializer<?> serializer) {
if (beanDesc.getBeanClass() == Asset.class) {
return new AssetXMLSerializer(new ExpandXmlBeanSerializer((BeanSerializerBase) serializer));
}
return serializer;
}
}
class ExpandXmlBeanSerializer extends XmlBeanSerializer {
public ExpandXmlBeanSerializer(BeanSerializerBase src) {
super(src);
}
@Override
public void serializeFields(Object bean, JsonGenerator gen0, SerializerProvider provider) throws IOException {
super.serializeFields(bean, gen0, provider);
}
}
class AssetXMLSerializer extends JsonSerializer<Asset> {
private final QName wrapper;
private final ExpandXmlBeanSerializer baseSerializer;
public AssetXMLSerializer(ExpandXmlBeanSerializer baseSerializer) {
this.baseSerializer = Objects.requireNonNull(baseSerializer);
String fields = String.join("_",
Stream.of(Asset.class.getDeclaredFields())
.map(Field::getName)
.collect(Collectors.toList()));
this.wrapper = new QName(fields);
}
@Override
public void serialize(Asset value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
ToXmlGenerator xmlGen = (ToXmlGenerator) gen;
xmlGen.writeStartObject();
xmlGen.startWrappedValue(wrapper, wrapper);
baseSerializer.serializeFields(value, gen, serializers);
xmlGen.finishWrappedValue(wrapper, wrapper);
xmlGen.writeEndObject();
}
}
@JsonRootName("ASSETS")
class Assets {
@JacksonXmlProperty(localName = "ASSET")
private List<Asset> assets = new ArrayList<>();
// getters, setters, toString
}
class Asset {
private String val1;
private String val2;
public Asset(String val1, String val2) {
this.val1 = val1;
this.val2 = val2;
}
// getters, setters, toString
}
另请参阅:
- Jackson xml and json root element
- Multiple Jackson XML Custom (XMLStreamWriter) Serialisers throws Exception
SpringBoot: Consume & Produce XML with a Custom Serializer + Deserializer