Spring RestTemplate搭配JAXB忽略空元素问题(无法修改生成POJO)
问题背景
通过XSD文件自动生成JAXB POJO(示例XSD及生成的POJO如下),使用RestTemplate发送POST请求时,需要忽略值为null/空的元素,但无法直接修改自动生成的POJO类,且升级JAXB、Spring等依赖后原忽略空值的配置失效。
示例XSD
<?xml version="1.0" encoding="utf-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified"> <xs:element name="XYZ"> <xs:complexType> <xs:sequence> <xs:element name="A" type="xs:string" minOccurs="0" /> <xs:element name="B" type="xs:string" minOccurs="0" /> </xs:sequence> </xs:complexType> </xs:element> </xs:schema>
生成的POJO
@XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "", propOrder = { "a", "b" }) @XmlRootElement(name = "XYZ") public class XYZ { @XmlElement(name = "A") protected String a; @XmlElement(name = "B") protected String b; // 省略getter/setter }
请求代码
HttpEntity<XYZ> requestHttpEntity = new HttpEntity<>(xyz); B response; try { ResponseEntity<B> responseEntity = restTemplate.exchange("someAddress", HttpMethod.POST, requestHttpEntity, B.class); response = responseEntity.getBody(); } catch (Exception e) { return null; }
解决方案
以下是几种无需修改POJO即可实现忽略null/空值元素的方案:
方案1:配置Jaxb2Marshaller扩展属性(适用于JAXB RI实现)
JAXB RI(GlassFish官方实现)提供了扩展属性com.sun.xml.bind.marshaller.omit-empty-element,设置为true可忽略null或空值元素。通过自定义Jaxb2Marshaller并替换RestTemplate的默认消息转换器实现:
// 1. 创建自定义Jaxb2Marshaller Jaxb2Marshaller marshaller = new Jaxb2Marshaller(); marshaller.setClassesToBeBound(XYZ.class, B.class); // 绑定需要序列化的POJO类 // 2. 设置忽略空值的扩展属性 marshaller.setMarshallerProperties(Map.of( "com.sun.xml.bind.marshaller.omit-empty-element", true )); // 3. 创建并配置消息转换器 Jaxb2RootElementHttpMessageConverter converter = new Jaxb2RootElementHttpMessageConverter(); converter.setMarshaller(marshaller); converter.setUnmarshaller(marshaller); // 4. 替换RestTemplate的默认JAXB消息转换器 RestTemplate restTemplate = new RestTemplate(); restTemplate.getMessageConverters().removeIf(c -> c instanceof Jaxb2RootElementHttpMessageConverter); restTemplate.getMessageConverters().add(converter);
方案2:使用MOXy外部映射配置(适用于EclipseLink MOXy实现)
如果项目使用EclipseLink MOXy作为JAXB实现,可通过外部XML映射文件配置忽略null值,无需修改POJO:
步骤1:引入MOXy依赖(若未引入)
<dependency> <groupId>org.eclipse.persistence</groupId> <artifactId>org.eclipse.persistence.moxy</artifactId> <version>匹配你的Spring版本</version> </dependency>
步骤2:创建外部映射文件(如jaxb-moxy.xml)
<?xml version="1.0"?> <xml-bindings xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm" package-name="你的POJO所在包路径"> <java-types> <java-type name="XYZ"> <java-attributes> <!-- nullable="false" 表示属性为null时不序列化该元素 --> <xml-element java-attribute="a" name="A" nullable="false"/> <xml-element java-attribute="b" name="B" nullable="false"/> </java-attributes> </java-type> </java-types> </xml-bindings>
步骤3:配置MOXy Marshaller到RestTemplate
MoxyMarshaller marshaller = new MoxyMarshaller(); marshaller.setContextPaths("你的POJO所在包路径"); marshaller.setMappingResources("jaxb-moxy.xml"); // 指定外部映射文件 Jaxb2RootElementHttpMessageConverter converter = new Jaxb2RootElementHttpMessageConverter(); converter.setMarshaller(marshaller); converter.setUnmarshaller(marshaller); RestTemplate restTemplate = new RestTemplate(); restTemplate.getMessageConverters().removeIf(c -> c instanceof Jaxb2RootElementHttpMessageConverter); restTemplate.getMessageConverters().add(converter);
方案3:切换为Jackson XML序列化(灵活通用)
使用Jackson的XML序列化模块,通过配置即可忽略null值,无需依赖JAXB特定实现:
步骤1:引入Jackson XML依赖
<dependency> <groupId>com.fasterxml.jackson.dataformat</groupId> <artifactId>jackson-dataformat-xml</artifactId> <version>匹配你的Spring版本</version> </dependency>
步骤2:配置XmlMapper并替换消息转换器
// 1. 配置XmlMapper,忽略null值并开启根节点包裹(适配@XmlRootElement) XmlMapper xmlMapper = new XmlMapper(); xmlMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); // 忽略null值属性 xmlMapper.configure(SerializationFeature.WRAP_ROOT_VALUE, true); // 包裹根节点 // 2. 创建Jackson XML消息转换器 MappingJackson2XmlHttpMessageConverter converter = new MappingJackson2XmlHttpMessageConverter(xmlMapper); // 3. 替换RestTemplate的默认消息转换器 RestTemplate restTemplate = new RestTemplate(); restTemplate.getMessageConverters().removeIf(c -> c instanceof Jaxb2RootElementHttpMessageConverter); restTemplate.getMessageConverters().add(converter);
注意事项
- 确认项目使用的JAXB实现:优先匹配对应方案(JAXB RI用方案1,MOXy用方案2);若无特殊依赖,方案3的Jackson XML配置更通用。
- 升级依赖后,原默认消息转换器的配置可能被重置,需确保自定义转换器被正确加载。
内容的提问来源于stack exchange,提问作者Ondrej Havlicek
相关产品推荐
相关产品推荐

