ClassLoaders not controlled by update4j
See original GitHub issueWe have update4j up and running and everything works nicely beside some classloader issues. Currently these 3pps does not work without some kind of workaround:
- Spring
- XStream
- Koloboke
Before loading the spring application context, which basically instantiate classes, we have to set the current classloader on the thread like this to workaround NoClassDefs:
Thread.currentThread().setContextClassLoader(tmpClassLoader);
the tmpClassLoader in the above case is taken from an already loaded class.
For XStream we have to do something similar, take the classloader from an already loaded class like this:
XStream xStream = new XStream();
xStream.setClassLoader(XStreamFactory.class.getClassLoader());
For Koloboke we haven’t figured out how to handle it.
If we look inside the koloboke code we see this:
private static class DefaultFactoryHolder {
private static final HashIntObjMapFactory defaultFactory =
ServiceLoader.load(HashIntObjMapFactory.class).iterator().next();
}
and when we look at JDK 11s ServiceLoader.load method, we see that the classloader is fetched like this:
@CallerSensitive
public static <S> ServiceLoader<S> load(Class<S> service) {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
return new ServiceLoader(Reflection.getCallerClass(), service, cl);
}
Digger deeper, if the current threads context classloader is null the ServiceLoader will use the system classloader:
if (cl == null) {
cl = ClassLoader.getSystemClassLoader();
}
All issues essentially have the same problem, getting the context classloader is either null or returns a classloader that is not controlled by update4j.
There must be a more generic way to do this. Can we configure update4j to make sure all returned classloaders are “valid” in the sense that they are controlled by update4j? Can we force each new thread to have update4js classloader when invoking:
Thread.currentThread().getContextClassLoader()
We are using update4j 1.44, AdoptOpenJDK 11.0.5 On the boot classpath we have 2 jar files: update4j and our custom boot lib, then we get the rest using the config.
If we run without update4j (using a common classpath) everythings works.
Issue Analytics
- State:
- Created 4 years ago
- Comments:38 (21 by maintainers)
Top GitHub Comments
I’m working on the other issues before releasing this. If you want, build from source yourself and either call:
in the first line of code in the bootstrap, or start the JVM with this flag:
There is much more to this feature, which I still have to document in the wiki, but this should be a quick-fix without the need to understand much of the classloading internals.
I got it working with below code. Let me know if you think there are cases where this won’t work. The important part is the setDelegate where it is switched out in the launcher, before starting the application. Don’t really like having to rely on reflection here, but don’t see any other solution to it.