JAXB生成Java类后,生成XML时如何保留XSD指定的元素名称并正确添加命名空间
JAXB生成Java类后,生成XML时如何保留XSD指定的元素名称并正确添加命名空间
看起来你遇到了JAXB序列化时命名空间丢失、元素名称自动小写的问题,我之前也踩过类似的坑,给你分步骤说下怎么解决:
先找问题根源
你的Java类注解看起来是对的,但序列化后出问题,主要有两个原因:
- 生成的类的**包级注解(package-info.java)**可能没配置正确,导致默认命名空间和元素格式不生效
- Spring RestTemplate默认的JAXB转换器没有正确处理命名空间和元素名称映射
解决步骤
1. 确保XJC生成的类注解完全正确
首先要让XJC生成符合要求的Java类,最好用**绑定文件(binding.xjb)**来约束生成规则,避免XJC默认的驼峰转换搞乱元素名称。
第一步:创建binding.xjb文件
放在src/main/resources/xjb目录下,内容如下:
<jaxb:bindings version="2.1" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <!-- 绑定目标XSD,设置全局规则 --> <jaxb:bindings schemaLocation="你的XSD文件路径(比如src/main/resources/xsd/your-schema.xsd)" node="/xsd:schema"> <!-- 指定生成的包名 --> <jaxb:schemaBindings> <jaxb:package name="com.yourcompany.model"/> <!-- 配置默认命名空间,前缀为空(即默认命名空间) --> <jaxb:xmlNs prefix="" namespace="https://transaction.elementexpress.com"/> </jaxb:schemaBindings> <!-- 强制所有元素使用qualified格式(继承默认命名空间) --> <jaxb:globalBindings elementFormDefault="qualified"/> <!-- 确保Application元素生成的Java属性名是application,但XML元素名保留XSD的Application --> <jaxb:bindings node="//xsd:element[@name='Application']"> <jaxb:property name="application"/> </jaxb:bindings> <!-- 确保ApplicationID元素的XML名称保留大写 --> <jaxb:bindings node="//xsd:element[@name='ApplicationID']"> <jaxb:property name="applicationID"/> </jaxb:bindings> </jaxb:bindings> </jaxb:bindings>
第二步:用Maven JAXB插件重新生成类
在pom.xml里配置插件,指定绑定文件:
<plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>jaxb2-maven-plugin</artifactId> <version>2.5.0</version> <executions> <execution> <goals> <goal>xjc</goal> </goals> </execution> </executions> <configuration> <schemaDirectory>${project.basedir}/src/main/resources/xsd</schemaDirectory> <bindingDirectory>${project.basedir}/src/main/resources/xjb</bindingDirectory> <bindingFiles>binding.xjb</bindingFiles> <packageName>com.yourcompany.model</packageName> </configuration> </plugin>
执行mvn jaxb2:xjc重新生成类,此时要检查两个关键点:
- 生成的
com.yourcompany.model/package-info.java必须有以下注解:@XmlSchema( namespace = "https://transaction.elementexpress.com", elementFormDefault = XmlNsForm.QUALIFIED ) package com.yourcompany.model; import javax.xml.bind.annotation.XmlNsForm; import javax.xml.bind.annotation.XmlSchema; Application类里的applicationID字段注解应该是:@XmlElement(name = "ApplicationID", namespace = "https://transaction.elementexpress.com", required = true) protected String applicationID;BatchTotalsQuery类里的application字段注解应该是:@XmlElement(name = "Application", namespace = "https://transaction.elementexpress.com", required = true) protected Application application;
2. 配置RestTemplate的JAXB转换器,强制输出命名空间
Spring默认的JAXB转换器可能不会主动输出默认命名空间,需要自定义Marshaller配置:
创建RestTemplate配置类
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.oxm.jaxb.Jaxb2Marshaller; import org.springframework.web.client.RestTemplate; import org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter; import java.util.HashMap; import java.util.Map; import javax.xml.bind.Marshaller; @Configuration public class RestTemplateConfig { @Bean public Jaxb2Marshaller jaxb2Marshaller() { Jaxb2Marshaller marshaller = new Jaxb2Marshaller(); // 指定生成类的包路径 marshaller.setPackagesToScan("com.yourcompany.model"); // 配置Marshaller属性,强制输出默认命名空间和格式化XML Map<String, Object> properties = new HashMap<>(); properties.put(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); properties.put(Marshaller.JAXB_DEFAULT_NAMESPACE, "https://transaction.elementexpress.com"); marshaller.setMarshallerProperties(properties); return marshaller; } @Bean public RestTemplate restTemplate(Jaxb2Marshaller jaxb2Marshaller) { RestTemplate restTemplate = new RestTemplate(); // 替换默认的JAXB转换器为自定义的 Jaxb2RootElementHttpMessageConverter converter = new Jaxb2RootElementHttpMessageConverter(); converter.setMarshaller(jaxb2Marshaller); converter.setUnmarshaller(jaxb2Marshaller); // 移除原来的JAXB转换器,添加自定义的 restTemplate.getMessageConverters().removeIf(c -> c instanceof Jaxb2RootElementHttpMessageConverter); restTemplate.getMessageConverters().add(converter); return restTemplate; } }
3. 用配置好的RestTemplate发送请求
现在再用你的代码发送请求,生成的XML就会符合要求了:
@Autowired private RestTemplate restTemplate; public void sendBatchQuery() { BatchTotalsQuery query = new BatchTotalsQuery(); Application application = new Application(); application.setApplicationID("20586"); query.setApplication(application); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_XML); HttpEntity<BatchTotalsQuery> entity = new HttpEntity<>(query, headers); // 发送请求 String response = restTemplate.postForObject("https://certtransaction.elementexpress.com", entity, String.class); }
此时生成的XML会是你想要的:
<BatchTotalsQuery xmlns="https://transaction.elementexpress.com"> <Application> <ApplicationID>20586</ApplicationID> </Application> </BatchTotalsQuery>
内容来源于stack exchange
相关产品推荐
相关产品推荐

