Spring Boot:使用自定义序列化器 + 反序列化器消费和生成 XML
Posted
技术标签:
【中文标题】Spring Boot:使用自定义序列化器 + 反序列化器消费和生成 XML【英文标题】:SpringBoot: Consume & Produce XML with a Custom Serializer + Deserializer 【发布时间】:2020-01-30 17:24:22 【问题描述】:我有一个 SpringBoot 服务:
型号
public class Payload
private final String id;
public Payload(String id)
this.id = id;
public String getId()
return this.id;
控制器
@RestController
@RequestMapping("/payload")
public class PayloadController
@RequestMapping(method = RequestMethod.POST)
public Payload post(@RequestBody final Payload payload)
return payload;
我需要这个控制器能够处理 JSON 和 XML 请求并以相同的格式响应。
如果我将 Content-Type
和 Accept
标头设置为正确的媒体类型,这可以正常工作。
但是,我的 XML 有效负载的结构需要与我的 JSON 稍有不同:
XML:
<Payload>
<id value="some-value"/>
</Payload>
JSON:
id: "some-value"
我如何确保我的id
被包装在一个 xml 节点中并具有“值”作为属性?
我曾尝试在我的Payload
类上使用@JsonSerialize
和@JsonDeserialize
注释,但一旦我这样做,当POST
ing XML 时出现以下错误
"timestamp": "2019-10-01T12:06:35.593+0000",
"status": 415,
"error": "Unsupported Media Type",
"message": "Content type 'application/xml;charset=UTF-8' not supported",
"path": "/payload"
【问题讨论】:
【参考方案1】:您需要注册2个转换器:
org.springframework.http.converter.json.MappingJackson2HttpMessageConverter
为JSON
。
org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter
为XML
。
因为Payload
类适合JSON
有效负载,您只需添加JsonCreator
和JsonProperty
注释即可使其工作:
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
public class Payload
private final String id;
@JsonCreator
public Payload(@JsonProperty(value = "id") String id)
this.id = id;
public String getId()
return this.id;
XML
payload 默认不适合,所以我们需要实现自定义序列化器:
import com.example.demo.model.Payload;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.dataformat.xml.ser.ToXmlGenerator;
import java.io.IOException;
public class PayloadXmlSerializer extends JsonSerializer<Payload>
@Override
public void serialize(Payload value, JsonGenerator gen, SerializerProvider serializers) throws IOException
ToXmlGenerator toXmlGenerator = (ToXmlGenerator) gen;
toXmlGenerator.writeStartObject();
toXmlGenerator.writeObjectFieldStart("id");
toXmlGenerator.setNextIsAttribute(true);
toXmlGenerator.writeFieldName("value");
toXmlGenerator.writeString(value.getId());
toXmlGenerator.setNextIsAttribute(false);
toXmlGenerator.writeEndObject();
toXmlGenerator.writeEndObject();
和反序列化器:
import com.example.demo.model.Payload;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonPointer;
import com.fasterxml.jackson.core.TreeNode;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.node.TextNode;
import java.io.IOException;
public class PayloadXmlDeserializer extends JsonDeserializer<Payload>
@Override
public Payload deserialize(JsonParser p, DeserializationContext ctxt) throws IOException
TreeNode root = p.readValueAsTree();
TreeNode value = root.at(JsonPointer.compile("/id/value"));
if (value.isMissingNode())
return new Payload(null);
TextNode textNode = (TextNode)value;
return new Payload(textNode.textValue());
最后,我们需要在上面注册HTTP
转换器和自定义序列化器/反序列化器:
import com.example.demo.model.Payload;
import com.example.jackson.PayloadXmlDeserializer;
import com.example.jackson.PayloadXmlSerializer;
import com.fasterxml.jackson.databind.module.SimpleModule;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.List;
@EnableWebMvc
@Configuration
public class WebConfig implements WebMvcConfigurer
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters)
//JSON
converters.add(new MappingJackson2HttpMessageConverter());
// XML
converters.add(new MappingJackson2XmlHttpMessageConverter(Jackson2ObjectMapperBuilder
.xml()
.modules(payloadModule())
.build()));
public SimpleModule payloadModule()
SimpleModule module = new SimpleModule();
module.addDeserializer(Payload.class, new PayloadXmlDeserializer());
module.addSerializer(Payload.class, new PayloadXmlSerializer());
return module;
另见:
Using Jackson to add XML attributes to manually-built node-tree 415 Unsupported MediaType for POST request in spring application Spring MVC【讨论】:
以上是关于Spring Boot:使用自定义序列化器 + 反序列化器消费和生成 XML的主要内容,如果未能解决你的问题,请参考以下文章
Spring boot 动态/注解自定义 JSON 反序列化器
杰克逊自定义反序列化器在 Spring Boot 中不起作用
如何在自定义反序列化器 Spring Boot 中读取路径变量或 URL 参数
Spring Boot - 自定义 JsonDeserializer 被忽略