JDK-6924232 : (reflect) IllegalAccessException on public final methods defined in package-access class
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.lang:reflect
  • Affected Version: 6u14
  • Priority: P4
  • Status: Open
  • Resolution: Unresolved
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2010-02-08
  • Updated: 2013-03-05
Related Reports
Relates :  
Relates :  
Description
FULL PRODUCT VERSION :
java version "1.6.0_14"
Java(TM) SE Runtime Environment (build 1.6.0_14-b08)
Java HotSpot(TM) Client VM (build 14.0-b16, mixed mode, sharing)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows XP [Version 5.1.2600]

A DESCRIPTION OF THE PROBLEM :
Invoking a public final method on a package local abstract class through a concrete implementing class results in an Exception similar to the following
can not access a member of class AbstractImpl with modifiers "public final".

However, removing the final modifier on the method results in a correct calling behaviour and the method may be called by reflection as expected.

I understand that this behaviour might result from the way java links virtual vs. final methods but nevertheless.
Shouldn't it be accessible in both ways? Calling on a concrecte object without reflection ofc works, too.

I have to break my class design to get this code running, and remove the final modifier and put it into the concrete class which is annoying.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
given the following:

package a;
class AbstractImpl {
  public final void final_method() {
    // do something
  }

  public void not_final() {
    // do something
  }
}

package a;
public class ConcrecteImpl extends AbstractImpl {
}



package b;

public static void main(String args[]) {
  ConcreteImpl p = new ConcreteImpl();
  // will work
  p.final_method();
  p.not_final() ;

Method not_final_method = obj.getClass().getMethod( "not_final_method", EMPTY_PARAMETERS );

  // will work
  not_final_method.invoke(p, EMPTY_PARAMETERS);


  Method final_method = obj.getClass().getMethod( "final_method", EMPTY_PARAMETERS );

  // wont work, crashes with illegalAccessException, can not access with modifier public final
  final_method.invoke(p, EMPTY_PARAMETERS);

}

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
I would expect that both methods could be called by reflection as they are when calling them through an object.
ACTUAL -
Only the method without the final modifier can be called.

ERROR MESSAGES/STACK TRACES THAT OCCUR :
java.lang.IllegalAccessException: Class Test can not access a member of class a.AbstractImpl with modifiers "public final"
	at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:65)
	at java.lang.reflect.Method.invoke(Method.java:588)

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
package a;
abstract class AbstractImpl {
  public final void final_method() {
    // do something
  }

  public void not_final() {
    // do something
  }
}

package a;
public class ConcrecteImpl extends AbstractImpl {
}



package b;
import a.*;

public class Test {
  public static void main(String args[]) {
    ConcreteImpl p = new ConcreteImpl();
    // will work
    p.final_method();
    p.not_final() ;


  Method not_final_method = obj.getClass().getMethod( "not_final_method",   EMPTY_PARAMETERS );
  not_final_method.invoke(p, EMPTY_PARAMETERS);


  Method final_method = obj.getClass().getMethod( "final_method", EMPTY_PARAMETERS );

  // wont work, crashes with illegalAccessException, can not access with modifier public final
  final_method.invoke(p, EMPTY_PARAMETERS);

}
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Remove the final modifier on the implementation of the method in the abstract class

Comments
EVALUATION javac (fix for 6342411) generates a bridge method when a public method is inherited from a non public class into a public class but not the final method.
22-07-2010

EVALUATION IllegalAccessException is thrown in this test case since b.Test is requesting to invoke a.AbstractImpl.final_method() but a.AbstractImpl is package-private class and not accessible from b.Test. The IllegalAccessException should provide a better message helping the diagnosis. The declaring class of the final_method is a.AbstractImpl whereas the declaring class of the non-final method is a.ConcreteImpl which is a public class and is accessible from b.Test.
22-07-2010

WORK AROUND Call final_method.setAccessible(true) to allow access.
22-07-2010