invokevirtual on package private override in different classloader

Jeffrey Sinclair jeff at cooljeff.co.uk
Fri Apr 10 19:34:16 PDT 2009


hotspot-dev,

I've been struggling to understand why HotSpot does not throw an
IllegalAccessError when a call is made to an override of a package
private method on an instance loaded by a different class loader. I was
hoping someone could explain to me in technical detail where I'm going
wrong because it appears to be a bug.

(all source code is pasted at the end of the mail)

I have a class called Square with a package private method named
getColour() which returns 'red'. I have a subclass of Square called
CustomSquare which overrides getColour() to return 'blue'. I have
another class called Printer which simply prints out getColour() for the
Square passed to it. I then have two test cases:

   * Printer.print(Square) is called with a CustomSquare instantiated in
the same ClassLoader as Printer.
   * Printer.print(Square) is called with a CustomSquare instantiated in
a different ClassLoader as Printer.

What I find is that I get 'blue' in the first test (as expected) and
'red' in the second test (not expected).

>From the Access Control constraints in the Linking section of the JVM
specification (5.4.4), I as expecting an IllegalAccessError to be thrown
because it states that a package private method is accessible to a class
if it is declared by a class in the same runtime package.

My understanding is that Printer is not in the same runtime package as
CustomSquare which explains why my override does not kick in, but it
does not explain why an IllegalAccessError is not thrown.

I was wondering if someone could explain the behaviour to me.

Regards,

Jeff

The source code:

public class Main {
  public static void main(String[] args) throws Exception {
    URL[] urls = new URL[]{new URL("path/to/CustomSquare")};
    URLClassLoader loader = new URLClassLoader(urls);	
    Class clazz =
loader.loadClass("uk.co.cooljeff.visibility.CustomSquare");
    Printer printer = new Printer();
    printer.print((Square)clazz.newInstance()); // 'red' gets printed
  }	
}

package uk.co.cooljeff.visibility;

public class Printer {
  public void print(Square square) {
    System.out.println(square.getColour());
  }
}

package uk.co.cooljeff.visibility;

public class CustomSquare extends Square {
  public CustomSquare() {
    super(5);
  }

  @Override
  public String getColour() {
    return "blue";
  }
}

package uk.co.cooljeff.visibility;

public class Square {
  private float length;

  public Square(float length) {
    this.length = length;
  }

  public float calculateArea() {
    return length * length;
  }

  String getColour() {
    return "red";
  }
}




More information about the hotspot-dev mailing list