question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

JAXB Implementation not found in Java 11 when using Failsafe with Retries & Spring Boot

See original GitHub issue

When using riptide-soap together with retries from riptide-failsafe in Java 11 on a packaged Spring Boot jar, the call fails with javax.xml.bind.JAXBException: Implementation of JAXB-API has not been found on module path or classpath. despite the correct JARs being in the classpath.

Description

In this specific combination:

  • riptide-soap
  • riptide-failsafe with retries enabled
  • Java 11
  • Packaged spring boot jar

The call to create a JAXBContext with the aforementioned message. If retries are disabled, everything works as expected.

The root cause of the issue seems like that Failsafe is using ForkJoinPool.commonPool() internally, resulting us in hitting https://github.com/spring-projects/spring-boot/issues/15737.

Possible Fix

I can think of two options:

  • Explicitly passing the current class’ class loader to JAXBContext.newInstance(). This requires us to switch to creating JAXBContext with contextPath instead of the class to be bound.
  • Explicitly supplying an Executor to Failsafe that creates threads with the proper context class loader.

I don’t know which of these options is better, but I’d be happy to implement the change if there is some consensus.

Steps to Reproduce

I can provide a sample project if needed

Your Environment

  • Version used: 3.0.0-RC.14

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Reactions:1
  • Comments:23 (16 by maintainers)

github_iconTop GitHub Comments

1reaction
whiskeysierracommented, Jan 15, 2021

Could we have a default TaskDecorator that we apply to each execution?

/**
 * @see <a href="https://github.com/zalando/riptide/issues/953">JAXB + ForkJoinPool</a>
 */
@API(status = EXPERIMENTAL)
@AllArgsConstructor
private final class PreserveContextClassLoader implements TaskDecorator {

    private final ClassLoader loader = Thread.currentThread().getContextClassLoader();

    @Override
    public <T> ContextualSupplier<T> decorate(final ContextualSupplier<T> supplier) {
        final Span span = tracer.activeSpan();

        return context -> {
            Thread.currentThread().setContextClassLoader(loader);
            return supplier.get(context);
        };
    }

}
1reaction
tobias-bahlscommented, Sep 25, 2020

That’s right, I got the classes confused. However it looks like Scheduler is able to just wrap Executor, so the points still stand.

I feel I should also document our workaround in case someone else has this problem: We’re essentially running fix (1). We added this class:

public class JaxbForkJoinWorkerThreadFactory implements ForkJoinWorkerThreadFactory {
    @Override
    public ForkJoinWorkerThread newThread(ForkJoinPool pool) {
        ForkJoinWorkerThread thread = new JaxbForkJoinWorkerThread(pool);
        thread.setContextClassLoader(Thread.currentThread().getContextClassLoader());
        return thread;
    }

    static class JaxbForkJoinWorkerThread extends ForkJoinWorkerThread {
        protected JaxbForkJoinWorkerThread(ForkJoinPool pool) {
            super(pool);
        }
    }
}

And configured this ThreadFactory in main before booting the Spring Application. It needs to be in main (as opposed to passing the system property via command line) because the class is only loaded after the spring boot launcher has run.

System.setProperty("java.util.concurrent.ForkJoinPool.common.threadFactory",JaxbForkJoinWorkerThreadFactory::class.qualifiedName!!)

In our case we also needed to override the default parallelism of the ForkJoinPool to force Failsafe to use the common pool.

System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", Math.max(2, Runtime.getRuntime().availableProcessors()).toString())

It’s all super hacky, but it works. But I will be able to sleep easier at night if we can remove this code and get this fixed in Riptide 😉

Read more comments on GitHub >

github_iconTop Results From Across the Web

Implementation of JAXB-API has not been found on module ...
We have a couple of projects using Java 11 with Spring WS and everything is working just fine. Also make sure that your...
Read more >
Implementation of JAXB-API has not been found on module ...
This article shows how to solve the popular JAXB exception Implementation of JAXB-API has not been found on module path or classpath ....
Read more >
From POJO to XML and Back with JAXB and Java 11+
Starting with Java 11+, you will have to add the JAXB API, as well as, the JAXB implementation as additional dependencies:
Read more >
Liberty features - IBM
Liberty feature WebSphere® Application Server Liberty Core WebSphere Application Ser... microProfile‑1.0 ✓ ✓ microProfile‑1.2 ✓ ✓ microProfile‑1.3 ✓ ✓
Read more >
Spring Framework Reference Documentation
Using the @Import annotation; Conditionally include @Configuration classes or @Bean methods; Combining Java and XML configuration.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found