From e6e0950a506d814415d8036e68e54d2034b6d3e7 Mon Sep 17 00:00:00 2001 From: Christof Rabensteiner Date: Thu, 22 Aug 2019 10:05:03 +0200 Subject: Fix: JAXB + Java >= 9 Class Loader Bug & Ensure Tomcat Deployment - Problem: Jaxb + JAVA >= 9 Runtime + Tomcat = ClassNotFoundException: ContextFactory. Reason: Apparently, jaxb uses the "wrong" classloader (the system classloader via the thread classloader) and this classloader does not know about jaxb api's and implementations at runtime since oracle decided to move jaxb* out of JRE. Solution: create a new thread, override the thread's "thread" classloader with the "class" classloader and do all jaxb interactions in that thread. See: https://sjhannah.com/blog/2018/11/21/jaxb-hell-on-jdk-9/ - Move "run jaxb interactions in own thread with class class loader" code into own component (JaxbClassNotFoundFix, runInTheadWithClassClassLoader) and wrap ClientFactory and Marshaller code into the "runInTheadWithClassClassLoader". - Ensure that app can be deployed in a Tomcat container (by following this guide: https://www.baeldung.com/spring-boot-war-tomcat-deploy) --- .../gv/egiz/moazs/util/JAXBClassNotFoundFix.java | 55 ++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 src/main/java/at/gv/egiz/moazs/util/JAXBClassNotFoundFix.java (limited to 'src/main/java/at/gv/egiz/moazs/util') diff --git a/src/main/java/at/gv/egiz/moazs/util/JAXBClassNotFoundFix.java b/src/main/java/at/gv/egiz/moazs/util/JAXBClassNotFoundFix.java new file mode 100644 index 0000000..9e72286 --- /dev/null +++ b/src/main/java/at/gv/egiz/moazs/util/JAXBClassNotFoundFix.java @@ -0,0 +1,55 @@ +package at.gv.egiz.moazs.util; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import java.util.function.Supplier; + +import static at.gv.egiz.moazs.MoaZSException.moaZSException; + +@Component +public class JAXBClassNotFoundFix { + + private static final Logger log = LoggerFactory.getLogger(JAXBClassNotFoundFix.class); + + /** + * Solves JAXB's "ClassNotFoundException: com.sun.xml.internal.bind.v2.ContextFactory" in Java >= 9 + * by running func in a dedicated thread which has its context classloader replaced with a classloader that finds + * the ContextFactory. + * + * See https://sjhannah.com/blog/2018/11/21/jaxb-hell-on-jdk-9/ + * Note: "runInTheadWithClassClassLoader" is not a typo. + * @param func function that is called in a dedicated thread. + * @param return value of func. + * @return + */ + public static A runInTheadWithClassClassLoader(Supplier func) { + + final Object[] result = new Object[1]; + final Exception[] error = new Exception[1]; + + Thread t = new Thread(() -> { + try { + result[0] = func.get(); + } catch (Exception ex) { + error[0] = ex; + } + }); + + t.setContextClassLoader(JAXBClassNotFoundFix.class.getClassLoader()); + t.start(); + + try { + t.join(); + } catch (InterruptedException ex) { + log.error("Interrupted. ", ex); + } + + if (error[0] != null) { + throw moaZSException("Could not run function.", error[0]); + } + + return (A)result[0]; + } +} -- cgit v1.2.3