SOAP请求元素名称与WSDL不一致问题排查
问题:SOAP请求XML元素名称与WSDL定义不符
通过IntelliJ导入第三方WSDL生成Java类后,发送SOAP请求时输出的XML元素名称和WSDL定义不一致。用SoapUI导入则能得到符合预期的元素名称,推测是编组过程忽略了@XmlElementRef注解,直接使用了变量类型。
预期输出XML:
<rxh2:Documents> <rxh2:Document> <rxh2:Base64String>JVBERi0xLjQN</rxh2:Base64String> <rxh2:DocumentType>Pdf</rxh2:DocumentType> </rxh2:Document> </rxh2:Documents>
实际输出XML:
<ns2:ArrayOfDocument> <ns2:Document> <ns2:Base64String>JVBERi0xLjYKJbiakp0KMS</ns2:Base64String> <ns2:DocumentType>Pdf</ns2:DocumentType> </ns2:Document> </ns2:ArrayOfDocument>
疑问:为何输出的元素名为ArrayOfDocument而非Documents?
pom.xml中wsimport插件配置
<plugin> <groupId>com.sun.xml.ws</groupId> <artifactId>jaxws-maven-plugin</artifactId> <version>4.0.2</version> <configuration> <wsdlUrls> <wsdlUrl> https://thewebsite/Integration/Service.OrderService.svc?wsdl </wsdlUrl> </wsdlUrls> <extension>true</extension> <verbose>true</verbose> <vmArgs> <vmArg>-Djavax.xml.accessExternalSchema=all</vmArg> </vmArgs> </configuration> <executions> <execution> <id>endpoint.hpc</id> <phase>generate-sources</phase> <goals> <goal>wsimport</goal> </goals> <configuration> <packageName>com.cgm.ms.script</packageName> <args> <arg>-B-XautoNameResolution</arg> </args> </configuration> </execution> </executions> </plugin>
生成的关键Java代码
对应属性定义:
@XmlElementRef(name = "Documents", namespace = "http://schemas.datacontract.org/2010/12/Service.Models.RFM", type = JAXBElement.class, required = false) protected JAXBElement<ArrayOfDocument> documents;
ArrayOfDocument类定义:
@XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "ArrayOfDocument", propOrder = { "document" }) public class ArrayOfDocument { @XmlElement(name = "Document", nillable = true) protected List<Document> document; ... }
问题原因与解决办法
原因分析
核心问题是对象编组时未正确使用JAXBElement包装实例。生成的代码中documents属性是JAXBElement<ArrayOfDocument>类型,这个类型的作用就是携带@XmlElementRef中指定的XML元素名称(即Documents)。如果直接把ArrayOfDocument实例赋值给documents,或编组时跳过JAXBElement包装,JAXB会忽略注解配置,直接根据ArrayOfDocument类的@XmlType注解生成ArrayOfDocument元素名。
解决办法
构建请求对象时,必须用JAXBElement包装ArrayOfDocument实例,步骤如下:
- 创建并填充
ArrayOfDocument实例:
ArrayOfDocument arrayOfDoc = new ArrayOfDocument(); Document doc = new Document(); doc.setBase64String("JVBERi0xLjQN"); doc.setDocumentType("Pdf"); arrayOfDoc.getDocument().add(doc);
- 使用自动生成的
ObjectFactory创建JAXBElement(wsimport会自动生成该类):
ObjectFactory factory = new ObjectFactory(); JAXBElement<ArrayOfDocument> documentsElement = factory.createDocuments(arrayOfDoc); request.setDocuments(documentsElement);
若找不到自动生成的createDocuments方法,可手动构建JAXBElement:
QName qName = new QName("http://schemas.datacontract.org/2010/12/Service.Models.RFM", "Documents"); JAXBElement<ArrayOfDocument> documentsElement = new JAXBElement<>(qName, ArrayOfDocument.class, arrayOfDoc); request.setDocuments(documentsElement);
这样编组时JAXB会读取JAXBElement中的元素名称,输出预期的<rxh2:Documents>节点,而非ArrayOfDocument对应的元素名。
内容的提问来源于stack exchange,提问作者Johan
相关产品推荐
相关产品推荐

