To illustrate my issue, I created a small spring boot sample application. The purpose of the application is to create a Jaxb2Marshaller
bean.
@SpringBootApplication
public class App implements CommandLineRunner {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
@Bean
public Jaxb2Marshaller jaxb2Marshaller() {
Jaxb2Marshaller bean = new Jaxb2Marshaller();
bean.setContextPath("ch.sahits.game.helloworld");
return bean;
}
@Override
public void run(String... args) throws Exception {
System.out.println("Started up");
}
}
This code fails to start up with the exception:
Caused by: java.lang.ClassNotFoundException: com.sun.xml.internal.bind.v2.ContextFactory
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:582)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:185)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:496)
at javax.xml.bind.ServiceLoaderUtil.nullSafeLoadClass(ServiceLoaderUtil.java:122)
at javax.xml.bind.ServiceLoaderUtil.safeLoadClass(ServiceLoaderUtil.java:155)
at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:174)
... 23 more
What I do not understand about this exception is why the com.sun.xml.internal.bind.v2.ContextFactory
is tried to instantiate? It has been suggested, that I also need a dependency for a runtime, so I added:
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.3.0</version>
</dependency>
But that only got me a different exception, trying to load a different class:
Caused by: java.lang.ClassNotFoundException: com.sun.xml.bind.v2.model.annotation.AnnotationReader
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:582)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:185)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:496)
... 39 more
Here is the complete pom.xml
:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>ch.sahits.game</groupId>
<artifactId>AddModuleDependencies</artifactId>
<version>1.0.0-SNAPSHOT</version>
<properties>
<cxf-xjc-plugin.version>2.3.0</cxf-xjc-plugin.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-oxm</artifactId>
<version>5.0.4.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.3.0</version>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<source>9</source>
<target>9</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-xjc-plugin</artifactId>
<version>${cxf-xjc-plugin.version}</version>
<executions>
<execution>
<id>generate-sources</id>
<phase>generate-sources</phase>
<goals>
<goal>xsdtojava</goal>
</goals>
<configuration>
<extensions>
<extension>org.apache.cxf.xjcplugins:cxf-xjc-dv:${cxf-xjc-plugin.version}</extension>
</extensions>
<xsdOptions>
<xsdOption>
<xsd>src/main/resources/helloworld.xsd</xsd>
<bindingFile>src/main/resources/jaxb-binding.xjb</bindingFile>
<packagename>ch.sahits.game.helloworld</packagename>
</xsdOption>
</xsdOptions>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
The simple solution of course is to add --add-modules java.xml.ws
as a VM option, but that is exactly what I am trying to get rid off to make my application future proof.
What dependency do I have to use to resolve this issue? Or do I have change the bean configuration, so that the proper classes are looked up (and not the ones from com.sun.xml...
)?
The MCVE for download as zip archive.
Try adding the following:
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-core</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>com.sun.activation</groupId>
<artifactId>javax.activation</artifactId>
<version>1.2.0</version>
</dependency>
jaxb-core
contains com.sun.xml.bind.v2.model.annotation.AnnotationReader
(and seems to be a required dependency of jaxb-runtime
, at least in your case), while javax.activation
is needed by jaxb-api
due to the usage of DataHandler
by the latter.
Also, there is no a single bean class, so the marshaller will fail initialization. I've added the following
@XmlRootElement
public class MyBean {
}
and replaced
bean.setContextPath("ch.sahits.game.helloworld");
with
bean.setClassesToBeBound(MyBean.class);
after which the application has started.
The following has worked for me
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.3.0</version>
</dependency>
来源:https://stackoverflow.com/questions/50139996/proper-way-to-use-spring-jaxb-marshaller-with-java-9-without-defining-additional