Returns the canonical instance of the default provider
for the service provider interface RMIClassLoaderSpi
.
If the system property java.rmi.server.RMIClassLoaderSpi
is not defined, then the RMIClassLoader
static
methods
loadClass(URL,String)
loadClass(String,String)
loadClass(String,String,ClassLoader)
loadProxyClass(String,String[],ClassLoader)
getClassLoader(String)
getClassAnnotation(Class)
If there is a security manager, its
checkPermission
method will be invoked with a
RuntimePermission("setFactory")
permission; this
could result in a SecurityException
.
The default service provider instance implements
RMIClassLoaderSpi
as follows:
The
RMIClassLoaderSpi.getClassAnnotation(Class)
method returns aString
representing the codebase URL path that a remote party should use to download the definition for the specified class. The format of the returned string is a path of URLs separated by spaces. The codebase string returned depends on the defining class loader of the specified class:
If the class loader is the system class loader (see
ClassLoader.getSystemClassLoader
), a parent of the system class loader such as the loader used for installed extensions, or the bootstrap class loader (which may be represented bynull
), then the value of thejava.rmi.server.codebase
property (or possibly an earlier cached value) is returned, ornull
is returned if that property is not set.Otherwise, if the class loader is an instance of
URLClassLoader
, then the returned string is a space-separated list of the external forms of the URLs returned by invoking thegetURLs
methods of the loader. If theURLClassLoader
was created by this provider to service an invocation of itsloadClass
orloadProxyClass
methods, then no permissions are required to get the associated codebase string. If it is an arbitrary otherURLClassLoader
instance, then if there is a security manager, itscheckPermission
method will be invoked once for each URL returned by thegetURLs
method, with the permission returned by invokingopenConnection().getPermission()
on each URL; if any of those invocations throws aSecurityException
or anIOException
, then the value of thejava.rmi.server.codebase
property (or possibly an earlier cached value) is returned, ornull
is returned if that property is not set.Finally, if the class loader is not an instance of
URLClassLoader
, then the value of thejava.rmi.server.codebase
property (or possibly an earlier cached value) is returned, ornull
is returned if that property is not set.For the implementations of the methods described below, which all take a
String
parameter namedcodebase
that is a space-separated list of URLs, each invocation has an associated codebase loader that is identified using thecodebase
argument in conjunction with the current thread's context class loader (seeThread.getContextClassLoader()
). When there is a security manager, this provider maintains an internal table of class loader instances (which are at least instances ofjava.net.URLClassLoader
) keyed by the pair of their parent class loader and their codebase URL path (an ordered list of URLs). If thecodebase
argument isnull
, the codebase URL path is the value of the system propertyjava.rmi.server.codebase
or possibly an earlier cached value. For a given codebase URL path passed as thecodebase
argument to an invocation of one of the below methods in a given context, the codebase loader is the loader in the table with the specified codebase URL path and the current thread's context class loader as its parent. If no such loader exists, then one is created and added to the table. The table does not maintain strong references to its contained loaders, in order to allow them and their defined classes to be garbage collected when not otherwise reachable. In order to prevent arbitrary untrusted code from being implicitly loaded into a virtual machine with no security manager, if there is no security manager set, the codebase loader is just the current thread's context class loader (the supplied codebase URL path is ignored, so remote class loading is disabled).The
RMIClassLoaderSpi.getClassLoader(String)
method returns the codebase loader for the specified codebase URL path. If there is a security manager, then if the calling context does not have permission to connect to all of the URLs in the codebase URL path, aSecurityException
will be thrown.The
RMIClassLoaderSpi.loadClass(String,String,ClassLoader)
method attempts to load the class with the specified name as follows:If thedefaultLoader
argument is non-null
, it first attempts to load the class with the specifiedname
using thedefaultLoader
, such as by evaluatingClass.forName(name, false, defaultLoader)If the class is successfully loaded from thedefaultLoader
, that class is returned. If an exception other thanClassNotFoundException
is thrown, that exception is thrown to the caller.Next, the
loadClass
method attempts to load the class with the specifiedname
using the codebase loader for the specified codebase URL path. If there is a security manager, then the calling context must have permission to connect to all of the URLs in the codebase URL path; otherwise, the current thread's context class loader will be used instead of the codebase loader.The
RMIClassLoaderSpi.loadProxyClass(String,String[],ClassLoader)
method attempts to return a dynamic proxy class with the named interface as follows:If the
defaultLoader
argument is non-null
and all of the named interfaces can be resolved through that loader, then,
- if all of the resolved interfaces are
public
, then it first attempts to obtain a dynamic proxy class (usingjava.lang.reflect.Proxy.getProxyClass(ClassLoader,Class[])
) for the resolved interfaces defined in the codebase loader; if that attempt throws anIllegalArgumentException
, it then attempts to obtain a dynamic proxy class for the resolved interfaces defined in thedefaultLoader
. If both attempts throwIllegalArgumentException
, then this method throws aClassNotFoundException
. If any other exception is thrown, that exception is thrown to the caller.- if all of the non-
public
resolved interfaces are defined in the same class loader, then it attempts to obtain a dynamic proxy class for the resolved interfaces defined in that loader.- otherwise, a
LinkageError
is thrown (because a class that implements all of the specified interfaces cannot be defined in any loader).Otherwise, if all of the named interfaces can be resolved through the codebase loader, then,
- if all of the resolved interfaces are
public
, then it attempts to obtain a dynamic proxy class for the resolved interfaces in the codebase loader. If the attempt throws anIllegalArgumentException
, then this method throws aClassNotFoundException
.- if all of the non-
public
resolved interfaces are defined in the same class loader, then it attempts to obtain a dynamic proxy class for the resolved interfaces defined in that loader.- otherwise, a
LinkageError
is thrown (because a class that implements all of the specified interfaces cannot be defined in any loader).Otherwise, a
ClassNotFoundException
is thrown for one of the named interfaces that could not be resolved.
SecurityException | if there is a security manager and the
invocation of its checkPermission method fails |
Diagram: ClassLoader