JDK-8044626 : Update RMI specifications to reflect modularization changes
  • Type: Enhancement
  • Component: core-libs
  • Sub-Component: java.rmi
  • Priority: P3
  • Status: Closed
  • Resolution: Fixed
  • Submitted: 2014-06-03
  • Updated: 2017-05-17
  • Resolved: 2017-02-07
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 10 JDK 9
10Fixed 9 b157Fixed
Related Reports
Relates :  
Relates :  
Sub Tasks
JDK-8173862 :  
Description
RMI will require changes to work with modules. This issue requests that the changes be scoped and sized. It may be that there are only small changes required but it might require some API/javadoc changes too.

Here is one example to consider:

import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
import javax.management.remote.JMXConnectorServer;
import javax.management.remote.JMXConnectorServerFactory;
import javax.management.remote.JMXServiceURL;

public class StubbsGazette {
    public static void main(String[] args) throws Exception {
        JMXServiceURL url = new JMXServiceURL("service:jmx:rmi://host");
        MBeanServer mbs = MBeanServerFactory.createMBeanServer();
        JMXConnectorServer server = JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbs);
        server.start();
    }
}


$ java StubbsGazette 
Exception in thread "main" java.rmi.StubNotFoundException: Stub class constructor not public: javax.management.remote.rmi.RMIServerImpl_Stub; nested exception is: 
	java.lang.IllegalAccessException: Class sun.rmi.server.Util (module java.rmi) can not access a member of class javax.management.remote.rmi.RMIServerImpl_Stub (module java.management) with modifiers "public"
	at sun.rmi.server.Util.createStub(Util.java:303)
	at sun.rmi.server.Util.createProxy(Util.java:139)
	at sun.rmi.server.UnicastServerRef.exportObject(UnicastServerRef.java:195)
	at java.rmi.server.UnicastRemoteObject.exportObject(UnicastRemoteObject.java:383)
	at java.rmi.server.UnicastRemoteObject.exportObject(UnicastRemoteObject.java:346)
	at javax.management.remote.rmi.RMIJRMPServerImpl.export(RMIJRMPServerImpl.java:118)
	at javax.management.remote.rmi.RMIJRMPServerImpl.export(RMIJRMPServerImpl.java:95)
	at javax.management.remote.rmi.RMIConnectorServer.start(RMIConnectorServer.java:404)
	at StubbsGazette.main(StubbsGazette.java:12)
Caused by: java.lang.IllegalAccessException: Class sun.rmi.server.Util (module java.rmi) can not access a member of class javax.management.remote.rmi.RMIServerImpl_Stub (module java.management) with modifiers "public"
	at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:142)
	at java.lang.reflect.AccessibleObject.slowCheckMemberAccess(AccessibleObject.java:295)
	at java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:287)
	at java.lang.reflect.Constructor.newInstance(Constructor.java:399)
	at sun.rmi.server.Util.createStub(Util.java:291)
	... 8 more

In this example then the exporting of the stub fails because the RMI module cannot read the management module. This may be a case where the Core Reflection usage needs to change so that RMI does the access check and suppresses the check (via setAccessible) when creating the stub.

Comments
Review thread: http://mail.openjdk.java.net/pipermail/core-libs-dev/2017-February/046178.html This also includes changes for JDK-8165649.
01-02-2017

The bug description has been updated to reflect the remaining work.
28-07-2016

I don't think there is anything critical in this area for the initial push to JDK 9 so I am moving this issue to the bill list.
04-11-2015

Current status of RMI in jake is that most regression tests pass, although there are four additional tests on the jake-specific problem list. This issue is mainly a documentation and specification issue. There are several subtle issues to be covered. Some are described in earlier comments. In particular, one is mentioned in Mandy's comment of 2015-07-12, updated 2015-09-09, having to do with proxy support for module-private interfaces. RMI may indeed need to support module-private interfaces. It's entirely possible for a Remote interface to be private within a package, as long as the Remote object and its clients all reside within the same package (though on different hosts!). In such cases these will all have "package-private" accessibility and thus won't be exported from the module. An additional issue raised by Alan (private mail) is that the Remote interface may reference types in parameters or return values, but these may have private implementations that need to be serialized and deserialized. So this impacts RMI's use of serialization as well. Also according to Alan, this isn't blocking anything, so it can be moved later, though of course it needs to be handled at some point. Adjusting due date closer to the end of 2015.
12-10-2015

Stuart - I see you've changed the due date on this one to Oct 16, 2015. Is there remaining work here?
10-10-2015

2015-07-12 RMI in JDK 8 uses RMI loader to define a dynamic proxy to implement any public remote interface. With modules, RMI has to be updated to handle the module-private type case; i.e. the remote interface is module-private. As a module-private type may reference other module-private types, JDK-8114859 updates sun.rmi.server.LoaderHandler to generate a dynamic proxy to implement a module-private interface in the same module as the interface [1]. JDK-8055626 should re-examine the module-private case and any spec change is required. Update on 2015-09-09 Proxy support for module-private interfaces is revisited [2]. For proxies that implement one or more module-private interface, it will be generated in a non-exported package in a dynamic module and the proxy class has access to all types referenced by all public method signatures of the proxy class. On the other hand, since the proxy class is module-private, it can't be instantiated via Constructor.newInstance. The sun.rmi.server.LoaderHandler change in [1] has been reverted. [1] http://closedjdk.us.oracle.com/jigsaw/jake/jdk/rev/e5b1ab7c97b1 [2] http://closedjdk.us.oracle.com/jigsaw/jake/jdk/rev/64f7037fb19e
10-09-2015

For dealing with static stubs, adding the Reads edge from java.rmi to the module containing the stub, if necessary, seems like the right thing to do. The patch given above that adds the Reads edge should be sufficient. If the stub is either non-public or not exported, the Class.forName() should fail. There's no need to call setAccessible(). I believe that static stubs must already be in the same package as the remote object they represent; implicitly, (1) they must also be public. I think that has been true independent of the module system, but this was probably never actually written down anywhere. If the remote object and its stub reside in a module, it follows that since they're in the same package, they must be in the same module. (Is that right?) If that's the case, then (2) the stub must also be exported from that module. I think it's reasonable to add (1) and (2) to the discussion in the UnicastRemoteObject class doc. This should be in the first hunk of bullet points where it describes how stub classes are found, loaded, and instantiated. [update 2015-08-21] I'm not sure the above is true. RMI does support package private remote interfaces, and it follows that in order to work, the server and clients must be in the same package (and module). In this case the stub must also be in the same package (and module). If everything is in the same package and module, then a private, static stub should also work. Thus, a static stub need not be public, and it need not be exported from its module.
22-08-2015

I've restored the synopsis on this bug to reflect the original intention. It is likely that a deeper analysis of RMI will be required to deal with issues such as JDK-8114859.
08-07-2015

At this time, we have the following files patched in jake to add read edges: src/java.rmi/share/classes/java/rmi/activation/ActivationGroup.java src/java.rmi/share/classes/java/rmi/activation/ActivationID.java src/java.rmi/share/classes/java/rmi/server/RMIClassLoader.java src/java.rmi/share/classes/sun/rmi/log/ReliableLog.java src/java.rmi/share/classes/sun/rmi/server/Activation.java src/java.rmi/share/classes/sun/rmi/server/Util.java Most of the tests are passing too but there are a number of issues that still need to diagnosed (there may be a javac issue amongst these). If the spec and docs changes are independent of modules then it would be good to get those into jdk9/dev.
02-06-2015

Since this is only a spec change, should it go into jdk9/dev instead of jake?
01-06-2015

Although we have a working solution in jake, we do need the RMI audited to identify whether there are any specification adjustments required.
11-01-2015

JDK-8046198 tracks the work to update j.l.reflect.Proxy, the non-public case is straight-forward as the proxy is generated into the same package as the interfaces, the public case is more difficult, esp. when it can be defined by an arbitrary loader. We are keeping the Proxy work separate to the RMI work for now.
06-07-2014

Re proxies, it appears that RMI supports use of both public and non-public Remote interfaces, so both cases should be supported by the module system.
23-06-2014

FYI. In order to create a proxy of a non-public interface, it must use the same class loader of the non-public interface; otherwise, Proxy.getProxyClass or Proxy.newProxyInstance will throw IAE. "same package" means same runtime package. In modular world, such dynamic generated proxy class would have to be in the same module as non-public proxy interface and the proxy class is non-public that can only be accessed by classes in the same runtime package.
07-06-2014

Re other uses of reflection, the first thing that comes to mind is java.rmi.server.RMIClassLoader (and sun.rmi.server.LoaderHandler, which is its default implementation). This is responsible for resolving and loading classes that appear as parameters or return values in RMI requests. These are usually resolved from RMI's codebase.
07-06-2014

Thanks Stuart. We will be tracking the work for Proxy in another issue. It would be good to also check other areas of RMI to see if there are Core Reflection uses that might need examination to work with module boundaries.
06-06-2014

The spec for how RMI locates static stubs is in the class doc for java.rmi.server.UnicastRemoteObject. (It discusses dynamic stubs as well.) Essentially the static stub is in the same package and is loaded by the same classloader as the "root class" i.e. the class of the instance being exported. Any class in module M that is using RMI has knowledge that it's using static stubs. Clearly such a module needs to express a dependency on the java.rmi module. It also seems reasonable to require such modules to export the package containing the stub to java.rmi. It seems like this ought to be enough to allow java.rmi access to stubs in module M, but apparently it isn't. Note, static stub support in RMI has been deprecated as of Java SE 8. It's unlikely to be removed soon, though, so we will probably need to continue to support static stubs for the foreseeable future. There is also an issue with stubs created using dynamic proxies. See java.lang.reflect.Proxy for a discussion of rules around how proxies are created. If the proxy implements a non-public interface, the proxy class is created within the same package as that interface. (There is no mention of which ClassLoader here that I can see.) It's not actually clear that RMI works with non-public interfaces. For public interfaces the situation might be a bit better, as the package of the proxy class in this case is unspecified. This may give us more flexibility. Still, how this interacts with the module system will need to be defined.
05-06-2014

javax.management.remote.rmi is exported by module java.management. Furthermore it is public and accessible to code in the unnamed module (code on the class path for example). The issue is that the RMI module (named java.rmi) does not require the management module (named java.management). This means that module java.management is not readable to module java.rmi, therefore the types in java.management are not accessible to RMI. Statically generated stubs are rare and will be rare for them to be in modules but this is something that RMI will need to be updated to work with. An option here is for RMI to check if the stub is in a module and if so then check that it is public and exported. It will then need to use setAccessible to suppress the access check in Core Reflection. Alternatively it may be as simple as invoking a TBD method that will make the management module readable at runtime. In any case, the implementation changes are likely to be very small. What is not clear is whether there are spec/javadoc changes needed. It would be useful to know if there is places in the spec where it might be necessary to say that if the stub is in a module that it must be in an exported package.
05-06-2014

In this case the stub class javax.management.remote.rmi.RMIServerImpl_Stub is statically generated and is part of the public API. As such, I think that the java.management module *must* export the stub along with all the rest of its public APIs. There may be other examples of where RMI has to change for modules, but I don't think this case is one of them.
03-06-2014