riptide: JAXB Implementation not found in Java 11 when using Failsafe with Retries & Spring Boot
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 creatingJAXBContext
withcontextPath
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
About this issue
- Original URL
- State: closed
- Created 4 years ago
- Reactions: 1
- Comments: 23 (16 by maintainers)
Could we have a default
TaskDecorator
that we apply to each execution?That’s right, I got the classes confused. However it looks like
Scheduler
is able to just wrapExecutor
, 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:
And configured this ThreadFactory in
main
before booting the Spring Application. It needs to be inmain
(as opposed to passing the system property via command line) because the class is only loaded after the spring boot launcher has run.In our case we also needed to override the default parallelism of the ForkJoinPool to force Failsafe to use the common pool.
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 😉