Update: Added some more info as the workaround is not working reliably
I have a RMI module that I load with a custom classloader vie spring beans. This class loader is also used to load that module.
The ClassLoader inherits from URLClassLoader. The parent class loader of that custom classloader is set to the AppClassLoader.
In this module, I start the RMI registry with the conxt classloader accordingly to this class loader.
Now, if I make RMI calls, the RMI registry:
- is able to spot classes in the path of the URLs that I provide to my class loader
- is NOT able to spot classes in the parent class loader.
By enabling debugging on RMI server side via
"-Djava.rmi.server.logCalls=true",
"-Dsun.rmi.server.logLevel=VERBOSE",
"-Dsun.rmi.loader.logLevel=VERBOSE",
I was able to verify that the correct class loader is used by the RMI registry (also the reference to the parent)
I tried adding the URLs from the AppClassLoader to my ClassLoader. First, it seemed to work but it onyl works randomly.
Currently I have the following output from the RMI logging
Nov 04, 2019 2:56:33 PM sun.rmi.server.LoaderHandler loadClass
FEINER: RMI TCP Connection(4)-10.45.42.206: (thread context class loader: class org.jvoicexml.config.JVoiceXmlClassLoader[repo=jsapi20,...,file:/C:/Users/dwalka/Documents/git/JVoiceXML/org.jvoicexml/build/libs/org.jvoicexml-0.7.9.jar,...,parent=sun.misc.Launcher$AppClassLoader@3d4eac69])
Nov 04, 2019 2:56:33 PM sun.rmi.server.LoaderHandler loadClass
FEIN: RMI TCP Connection(4)-10.45.42.206: class "org.jvoicexml.UuidSessionIdentifer" not found via codebase
java.lang.ClassNotFoundException: org.jvoicexml.UuidSessionIdentifer
The parent class loader looks as follows
2019-11-04T14:56:08,505 [JVoiceXmlMain ] INFO cexml.jndi.classserver.ClassloaderServer ( 56) - parent class loader 'sun.misc.Launcher$AppClassLoader@3d4eac69'
...
2019-11-04T14:56:08,506 [JVoiceXmlMain ] INFO cexml.jndi.classserver.ClassloaderServer ( 64) - parent class loader entry: 'file:/C:/Users/dwalka/Documents/git/JVoiceXML/org.jvoicexml/build/libs/org.jvoicexml-0.7.9.jar'
...
Side note: Classes from the JDK like java.net.URI are found
The jar contains the class
C:\Users\dwalka\Documents\git\JVoiceXML\org.jvoicexml\build\libs>jar -tf org.jvoicexml-0.7.9.jar | findstr "UuidSessionIdentifer"
org/jvoicexml/UuidSessionIdentifer.class
I did some unit tests to ensure that this works (without RMI). It finds classes
- in the same jar
- from the jar under discussion
- from other jars not in the CLASSPATH
Here is my ClassLoader
public final class JVoiceXmlClassLoader extends URLClassLoader {
/** The repository that this class loader is responsible for. */
private final String repository;
/**
* Constructs a new object.
* @param parent the parent class loader.
*/
public JVoiceXmlClassLoader(final ClassLoader parent) {
this(parent, null);
}
/**
* Constructs a new object.
* @param parent the parent class loader.
* @param repo the repository that this class loader is responsible for
*/
public JVoiceXmlClassLoader(final ClassLoader parent, final String repo) {
super(new URL[0], parent);
repository = repo;
}
/**
* Retrieves the used repository
* @return the repository.
* @since 0.7.9
*/
public String getRepository() {
return repository;
}
/**
* {@inheritDoc}
*/
@Override
public void addURL(final URL url) {
super.addURL(url);
}
}
A security manager is set
"-Djava.security.manager",
"-Djava.security.policy=${project(':org.jvoicexml').buildDir}/config/jvoicexml.policy",
and the policy file is very permissive
grant {
permission java.security.AllPermission;
};
The weird thing is that it was working previously without problems. Changes that I made since then
- Switch to Windows 10
- In the meantime I verified the same issue happens under Linux (Ubuntu)
- Update to Gradle 5.4.1