BenHT
BenHT

Reputation: 113

docx4j-JAXB-MOXy keeps trying to use glassfix.jaxb.runtime after upgrading to Spring Boot 3/jakarta.xml.bind-api 4

Using docx4j-JAXB-MOXy I upgraded to Spring Boot 3.3.0 but this also changed the jakarta.xml.bind-api dependency version to 4.0.2 (managed by Spring I guess).

The result (below) is that calls to get the jaxb context (eg org.docx4j.jaxb.Context) fail to get the desired value (org.eclipse.persistence.jaxb.JAXBContext, usually set by NamespacePrefixMapperUtils) but instead gives errors about the glassfish context which is obviously missing and not the right context anyway.

Setting jakarta.xml.bind-api back to version 3.0.1 makes it work without errors but I couldn't find any documentation saying this was necessary, which it seems to be which Spring Boot 3.3.0.

To ask an actual question - Is there another solution?

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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.3.0</version>
        <!-- previous version>2.7.18</version-->
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    
    <groupId>com.example</groupId>
    <artifactId>rest-service-complete</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>rest-service-complete</name>
    <description>Demo project for Spring Boot</description>
    
    <properties>
        <java.version>14</java.version>
    </properties>
    
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.docx4j</groupId>
            <artifactId>docx4j-JAXB-MOXy</artifactId>
            <version>11.4.11</version>
        </dependency>
        <dependency>
                <groupId>jakarta.xml.bind</groupId>
                <artifactId>jakarta.xml.bind-api</artifactId>
                <!-- NB works as expected for version 3.0.1, 4.0.2 seems to be managed by Spring -->
                <version>4.0.2</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

simple Java controller to load and save a docx :

package com.example.restservice;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.util.concurrent.atomic.AtomicLong;

import org.docx4j.openpackaging.exceptions.Docx4JException;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class GreetingController {
    private static final int bufferSize = 8 * 1024 * 1024;
    private final AtomicLong counter = new AtomicLong();

    @GetMapping("/greeting")
    public String greeting() throws FileNotFoundException, Docx4JException {
        File inputFile = new File("c:/tmp/input.docx");
        WordprocessingMLPackage doc = WordprocessingMLPackage.load(inputFile);

        File finalFile = new File("c:/tmp/output.docx");
        BufferedOutputStream finalStream = new BufferedOutputStream(new FileOutputStream(finalFile.getAbsolutePath()), bufferSize);
        doc.save(finalStream);
        
        return "Hello " + counter.incrementAndGet() + " World";
    }
}

stacktrace result :

jakarta.xml.bind.JAXBException: Implementation of Jakarta XML Binding-API has not been found on module path or classpath.
 - with linked exception:
[java.lang.ClassNotFoundException: org.glassfish.jaxb.runtime.v2.ContextFactory]
    at jakarta.xml.bind.ContextFinder.newInstance(ContextFinder.java:142)
    at jakarta.xml.bind.ContextFinder.find(ContextFinder.java:340)
    at jakarta.xml.bind.JAXBContext.newInstance(JAXBContext.java:392)
    at org.docx4j.jaxb.Context.<clinit>(Context.java:121)
    at org.docx4j.openpackaging.contenttype.ContentTypeManager.parseContentTypesFile(ContentTypeManager.java:858)
    at org.docx4j.openpackaging.io3.Load3.get(Load3.java:146)
    at org.docx4j.openpackaging.packages.OpcPackage.load(OpcPackage.java:572)
    at org.docx4j.openpackaging.packages.OpcPackage.load(OpcPackage.java:421)
    at org.docx4j.openpackaging.packages.OpcPackage.load(OpcPackage.java:298)
    at org.docx4j.openpackaging.packages.OpcPackage.load(OpcPackage.java:276)
    at org.docx4j.openpackaging.packages.WordprocessingMLPackage.load(WordprocessingMLPackage.java:170)
    at com.example.restservice.GreetingController.greeting(GreetingController.java:22)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:568)
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:255)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:188)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:118)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:926)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:831)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1089)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:979)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014)
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:903)
    at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:564)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885)
    at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:195)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
    at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:482)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:344)
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:389)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:896)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1741)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)
    at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1190)
    at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63)
    at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: java.lang.ClassNotFoundException: org.glassfish.jaxb.runtime.v2.ContextFactory
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
    at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520)
    at jakarta.xml.bind.ServiceLoaderUtil.nullSafeLoadClass(ServiceLoaderUtil.java:113)
    at jakarta.xml.bind.ServiceLoaderUtil.safeLoadClass(ServiceLoaderUtil.java:146)
    at jakarta.xml.bind.ContextFinder.newInstance(ContextFinder.java:139)
    ... 61 more

Upvotes: 0

Views: 227

Answers (1)

JasonPlutext
JasonPlutext

Reputation: 15878

Following Detect version's origin of a managed Maven dependency and including in the pom:

<dependency>
   <groupId>jakarta.xml.bind</groupId>
   <artifactId>jakarta.xml.bind-api</artifactId>
</dependency>

then running mvn help:effective-pom -Dverbose we can see:

<version>4.0.2</version>  <!-- org.springframework.boot:spring-boot-dependencies:3.3.0, line 1028 -->

so v4.0.2 of jakarta.xml.bind-api is a dep of org.springframework.boot:spring-boot-dependencies:3.3.0

You'd need to exclude that, possibly by editing or replacing the parent pom.

Unless you need/want to use MOXy for some reason, you could workaround by using docx4j-JAXB-ReferenceImpl instead.

docx4j 11.5.0 when released will use v4.0.2 of jakarta.xml.bind-api and that release will play nice with MOXy.

Upvotes: 1

Related Questions