Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do I get a BootstrapMethodError when trying to call a super class's protected method using method reference from an inner class?

Tags:

java

java-8

In Java 8, given a super class Super in package a and a sub class Sub in package b, who has an inner class SubInner:

// Super.java
package a;

public abstract class Super {
   private long value;
   protected final void setValue(long value) {
      this.value = value;
   }
}

//Sub.java
package b;

public class Sub extends Super {
  public void foo() {
    new SubInner().foo();
  }
  private class SubInner {
    void foo() {
      Optional.of(1L).ifPresent(Sub.this::setValue); // Will throw IllegalAccessError at runtime.
      Optional.of(1L).ifPresent(t -> setValue(t)); // However, lambda works.
      setValue(1L); // also works.
    }
  }
}

My question is, why method reference fails to work in this case while normal method call have access to super class method setValue?

Plus, if I try to do Sub.super::setValue, the code doesn't compile and the error seems to be in-line with the runtime error: setValue has protected access in a.Super.

Exception in thread "main" java.lang.BootstrapMethodError: java.lang.IllegalAccessError: tried to access method a.Super.setValue(J)V from class b.Sub$SubInner
    at b.Sub$SubInner.foo(Sub.java:14)
    at b.Sub.foo(Sub.java:10)
    at b.Sub.main(Sub.java:22)
Caused by: java.lang.IllegalAccessError: tried to access method a.Super.setValue(J)V from class b.Sub$SubInner
    at java.lang.invoke.MethodHandleNatives.resolve(Native Method)
    at java.lang.invoke.MemberName$Factory.resolve(MemberName.java:975)
    at java.lang.invoke.MemberName$Factory.resolveOrFail(MemberName.java:1000)
    at java.lang.invoke.MethodHandles$Lookup.resolveOrFail(MethodHandles.java:1394)
    at java.lang.invoke.MethodHandles$Lookup.linkMethodHandleConstant(MethodHandles.java:1750)
    at java.lang.invoke.MethodHandleNatives.linkMethodHandleConstant(MethodHandleNatives.java:477)
    ... 3 more
like image 764
xiaofeng.li Avatar asked Apr 29 '19 07:04

xiaofeng.li


1 Answers

It very much looks like this bug, which is fixed...

I don't have java-9 locally to confirm that it is indeed fixed in java-9 as the bug states; but works just fine under java-11 and java-12. It would not be the first time there are anomalies in how a lambda/method references are treated by javac/java; usually a lambda is a workaround for the method reference and vice-versa.

like image 66
Eugene Avatar answered Nov 15 '22 17:11

Eugene