If you receive
null for every attribute to your SOAP requests in Spring, after upgrading JDK, this is what you need to do
If you have a SOAP service written in Java using Spring, you have written methods that are called with Java objects representing the body of the SOAP request. If, after upgrading from Java 8 to Java 11, you see that every attribute of those Java objects is null, adding the following to your Maven file is the solution:
<plugin> <groupId>com.google.code.maven-replacer-plugin</groupId> <artifactId>maven-replacer-plugin</artifactId> <version>1.3.5</version> <executions> <execution> <id>make-namespaces-visible-to-soap</id> <phase>process-sources</phase> <goals><goal>replace</goal></goals> <configuration> <includes> <include>target/generated-sources/jaxb/com/myproject/package-info.java</include> </includes> <replacements> <replacement> <token>@javax.xml.bind.annotation.XmlSchema\(</token> <value>@javax.xml.bind.annotation.XmlSchema(elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED, </value> </replacement> </replacements> </configuration> </execution> </executions> </plugin>
Since JDK9, Project Jigsaw is part of the JDK. That means, that certain functionality which was previously provided in the JDK is no longer available by default. One such functionality is the XJC tool and JAXB library used by Spring to provide SOAP services:
- XJC generates Java classes from XML schemas (XSD) during the build process.
- JAXB allows these Java classes to be populated from XML at runtime e.g. by incoming SOAP requests.
These were previously included in the JDK, and are now available on Maven to be added to your
I don't know what versions of these two modules were included in JDK8 (I suppose they were just "JDK8 version") but the versions of JAXB runtime on Maven Central (needed at runtime) are 2.2, 2.3 and 2.4. (I tried all of them.)
SOAP requests use namespaces to differentiate the SOAP envelope (containing the request), the security information, and your body. This is a good thing, and anyway even if it wasn't, Spring complains otherwise:
Caused by: java.lang.IllegalArgumentException: class path resource [sap.xsd] has no targetNamespace
After a full day of debugging and reading source code, the conclusion I came to is that this is what's going on:
- When the SOAP request is sent, each element contains the appropriate namespace. This is interpreted correctly by Spring.
- JAXB, at runtime, attempts to take values from the XML supplied in the SOAP request, and place them into objects (of classes generated from the XSD by XJC).
- JAXB does not have access to the XSD definition at runtime; all it has access to is the generated classes. It attempts to read the XML namespace out of these generated classes.
- The XML namespace is written by XJC into a generated
package-info.javafile next to the Java classes representing each XSD element. This file has an
@XmlSchemaannotation, which correctly contains the XML namespace.
- However, JAXB at runtime fails to read this namespace from the
package-info.java, meaning it thinks that the classes to be populated from the request represent XML without a namespace.
- Seeing that none of the elements in the SOAP request (with namespace) match the elements in the Java objects to be populated (without namespace), it does not populate them.
- Therefore, your Java service method is called with an object of the right class, but whose every attribute is
The code to extract, from the generated Java class, the XML attribute that each Java attribute represents, is here. You can see it checks for the package annotation
@XmlSchema annotation has an attribute
elementFormDefault. This is default
UNSET, the JAXB code ignores the namespace extracted from the
@XmlSchema. That's the problem.
I don't understand why you would want to ignore namespaces. Perhaps to workaround some other bug?
There is no way I can find to alter the XJC generation process to add that attribute to the
@XmlSchema annotation on the generated
package-info.java, so I alter the files with that "sed"-like file manipulation.
- How to write a SOAP service in Spring. Great tutorial, but only covers JDK8, that stuff doesn't work with JDK11. I'm hoping they update it soon, JDK8 is already past end-of-life.
- If you get the error
Prefix '' is already bound to '', see here. Downgrade to jaxb2-maven-plugin version 1.x, or for 2.x you need to add an extra useless
dummy.xsdto your XSD directory.
- If you get errors about the paths of your XSD files being wrong e.g. your files are in
/opt/foo/x.xsdand it complains about
/home/asmith/opt/foo/x.xsdnot being found, downgrade to jaxb2-maven-plugin version 1.x. If you use 2.x then it finds files relative to your current working directory and not pom.xml.