4

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.

hotzst
  • 7,238
  • 9
  • 41
  • 64
  • Taking a look intor `ContextFinder` I saw this line `Class spFactory = ServiceLoaderUtil.safeLoadClass(className, PLATFORM_DEFAULT_FACTORY_CLASS, classLoader);` which basically hard wires the factory to `com.sun.xml.internal.bind.v2.ContextFactory`. So this might actually be an issue with the JDK 9 itself. – hotzst May 03 '18 at 18:47
  • Turns out that I only added the runtime dependency in the dependencyManagement section, but in the actual sub-modules `jaxb-runtime` was missing. – hotzst Nov 07 '18 at 17:01

3 Answers3

4

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.

Roman Puchkovskiy
  • 11,415
  • 5
  • 36
  • 72
  • The beans are actually created by Maven, that is the reason, that they are not defined explicitly. – hotzst May 05 '18 at 14:33
  • @hotzst If I understand correctly, as long as `ch.sahits.game.helloworld` contains `ObjectFactory.class` or `jaxb.index` (and Maven should generate them as well), it shoud work with `bean.setContextPath("ch.sahits.game.helloworld")`. I just switched to `setClassesToBeBound()` to check that it works in the simplest way possible. – Roman Puchkovskiy May 05 '18 at 15:47
  • 1
    When starting from within IntelliJ I still get the same error. However when building an executable jar with spring boot I get `java.lang.ClassNotFoundException: com.sun.istack.Pool`. This indicates that in the IDE, there is an issue with the classpath. – hotzst May 05 '18 at 18:36
4

The following has worked for me

<dependency>
  <groupId>org.glassfish.jaxb</groupId>
  <artifactId>jaxb-runtime</artifactId>
  <version>2.3.0</version>
</dependency>
Philippe Marschall
  • 4,452
  • 1
  • 34
  • 52
  • Version 3.0.0 is now available. You may need to upgrade a lot of libraries when switching since they use jakarta instead of javax. See useful answer: https://stackoverflow.com/a/54574003/13752392 – aarowman Mar 09 '21 at 20:29
0

Connecting "Spring OXM" helped me:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-oxm</artifactId>
</dependency>