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); private JAXBClassNotFoundFix() {} /** * 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); throw moaZSException("Interrupted. ", ex); } if (error[0] != null) { throw moaZSException("Could not run function.", error[0]); } return (A)result[0]; } }