8

I have the following issue: I have a class, trying to use reflection to call one of its OWN protected methods, and I'm getting an exception: java.lang.IllegalAccessException: access to method denied

Can someone maybe shed some light on this?

The base class:

public abstract class BaseReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        // invoke the correct event method:
        Method method;
        try {
            method = this.getClass().getDeclaredMethod("testMethod");
            method.invoke(this);
        } catch (Throwable ex) {
             // ... display exception message
        }
    }

    protected void testMethod() {
    }

}

The derived concrete class:

class MyReceiver extends BaseReceiver {
    @Override
    protected void testMethod() {
        // display error message
    }
}
mchen
  • 9,808
  • 17
  • 72
  • 125
Sagi Mann
  • 2,967
  • 6
  • 39
  • 72

2 Answers2

17

Protected methods are accessible just from the package, the the class itself or the classes that extends it.

As far as I can suppose (based on the Exception) your extended class (MyReceiver) is in another package then the super class (BaseReceiver). Meaning:

  1. MyReceiver and BaseReceiver isn't in the same package;
  2. BaseReceiver doesn't extends MyReceiver;

Now, as you can see on your code, you are doing: method = this.getClass().getDeclaredMethod("testMethod"); this seems ok, but it isn't what you intend. As this method will return MyReceiver.testMethod() method, and this is not accessible from BaseReceiver (as you can see you are using this.getClass(), what returns the instance class, in this case MyReceiver).

You could do something:

...
method = BaseReceiver.class.getDeclaredMethod("testMethod");
...

with this you are instructing that you want the protected method being declared on BaseReceiver class. Of course when you invoke it later with method.invoke(this); you will invoke the overridden method.

But it doesn't make sense to use reflection in such case, as you have testMethod() available, and invoking it (simple as this.testMethod()) you will invoke the overridden one.

Another possibility is to setAccessible(true) on the method like:

method = getClass().getDeclaredMethod("testMethod");
method.setAccessible(true);
method.invoke(this);
Francisco Spaeth
  • 23,493
  • 7
  • 67
  • 106
1

The static type of this in BaseReceiver is BaseReceiver, so you wouldn't normally have access to MyReceiver.testMethod. Apart from which, the reflection APIs check the caller class, not instance (which is nuts itself considering what reflection is for).

You should be able to use BaseReceiver.testMethod.

Reflection is a bad idea in most (but not all) cases it is used.

Tom Hawtin - tackline
  • 145,806
  • 30
  • 211
  • 305