javainheritancevisibilitysun

Subclassing sun.* class in same package gives IllegalAccessError


Foreword:

  1. What am I going to show you is WRONG and I'm well aware of how bad I am for breaking encapsulation by doing such foolish thing.
  2. I'm not trying to solve any more general I/O problem. It's just an experiment.

I'm trying to sub-class sun.nio.ch.SourceChannelImpl which is package private class with package private constructor present in JDK (in rt.jar) so I have to create it in sun.nio.ch package.

Here is my sub-class:

package sun.nio.ch;
import java.io.FileDescriptor;
import java.nio.channels.spi.SelectorProvider;
class MySourceChannel extends SourceChannelImpl {
  public MySourceChannel(SelectorProvider sp, FileDescriptor fd) {
    super(sp, fd);
  }
}

Here is my simple test:

package sun.nio.ch;
import java.io.FileDescriptor;
public class Main {
  public static void main(String[] args) {
    new MySourceChannel(null, FileDescriptor.in);
  }
}

And here's the failure:

Exception in thread "main" java.lang.IllegalAccessError: class sun.nio.ch.MySourceChannel cannot access its superclass sun.nio.ch.SourceChannelImpl
        at java.lang.ClassLoader.defineClass1(Native Method)
        at java.lang.ClassLoader.defineClass(ClassLoader.java:800)
        at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
        at java.net.URLClassLoader.defineClass(URLClassLoader.java:449)
        at java.net.URLClassLoader.access$100(URLClassLoader.java:71)
        at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
        at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
        at sun.nio.ch.Main.main(Main.java:5)

It's probably not you can't define class in JDK package XYZ ((java|sun).*) type of problem because otherwise I'd get

java.lang.SecurityException: Prohibited package name: XYZ

Main class works fine in this package.

I've also tried to disable security checks by setting Policy allowing everything and that didn't help neither. I've also tried System.setSecurityManager(null); (I'm not sure if this actually disables it) and it didn't help neither.

What's the problem? How can I fix it please?

I've tried it with JDK 1.7.0_45, both Oracle and OpenJDK.


Solution

  • SourceChannelImpl is a "package private" class. In the JVM a package is always loaded by a single class loader. If you have two packages with the same name loaded by different class loaders, they are not the same package.

    You can fix this by loading some or all of your code in the bootstrap class loader with -Xbootclasspath/a:mybootspath.