0

I am trying to get a MethodHandle for any of the constructors of the com.sun.tools.javac.code.TypeMetadata.Annotations record on JDK 21. Here is the source code of TypeMetadata (from OpenJDK):

https://github.com/openjdk/jdk/blob/acd93102348f592d6f2e77a4bff6037edf708d55/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeMetadata.java

Here is my code:

import com.sun.tools.javac.code.TypeMetadata;
import java.lang.invoke.*;
import java.util.*;

class TestMH {
  public static void main(String[] args) throws Throwable {
    MethodHandles.Lookup lookup = MethodHandles.lookup();
    MethodType mt = MethodType.methodType(void.class);
    MethodHandle mh = lookup.findConstructor(TypeMetadata.Annotations.class, mt);
    System.out.println(mh);
  }
}

I compile by doing javac --add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED TestMH.java. Here is the output of java --add-opens=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED TestMH:

Exception in thread "main" java.lang.IllegalAccessException: no such constructor: com.sun.tools.javac.code.TypeMetadata$Annotations.<init>()void/newInvokeSpecial
    at java.base/java.lang.invoke.MemberName.makeAccessException(MemberName.java:911)
    at java.base/java.lang.invoke.MemberName$Factory.resolveOrFail(MemberName.java:994)
    at java.base/java.lang.invoke.MethodHandles$Lookup.resolveOrFail(MethodHandles.java:3750)
    at java.base/java.lang.invoke.MethodHandles$Lookup.findConstructor(MethodHandles.java:2837)
    at TestMH.main(TestMH.java:9)
Caused by: java.lang.IllegalAccessError: class TestMH tried to access method 'void com.sun.tools.javac.code.TypeMetadata$Annotations.<init>()' (TestMH is in unnamed module of loader 'app'; com.sun.tools.javac.code.TypeMetadata$Annotations is in module jdk.compiler of loader 'app')
    at java.base/java.lang.invoke.MethodHandleNatives.resolve(Native Method)
    at java.base/java.lang.invoke.MemberName$Factory.resolve(MemberName.java:962)
    at java.base/java.lang.invoke.MemberName$Factory.resolveOrFail(MemberName.java:991)
    ... 3 more

Is there some way to get around this IllegalAccessError, beyond the --add-opens flag? Or is this a fundamental limitation due to the modules?

msridhar
  • 2,846
  • 4
  • 22
  • 23

1 Answers1

3

A full-privilege Lookup can only access things that normal Java code in the lookupClass() could do as well.

In your case, the lookupClass is your class: TestMH.

The no-argument constructor of TypeMetadata.Annotations is package-private - it can't be accessed from outside of that package.

A Lookup respects that limitation - even if the package is open, you have to explicitly "teleport" into the target package:

MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandles.Lookup targetLookup = MethodHandles.privateLookupIn(TypeMetadata.Annotations.class, lookup);
MethodType mt = MethodType.methodType(void.class);
MethodHandle mh = targetLookup.findConstructor(TypeMetadata.Annotations.class, mt);
Johannes Kuhn
  • 14,778
  • 4
  • 49
  • 73
  • 1
    An other way is to stick with the canonical constructor - which must be public. This means, exporting (both at compile and runtime) both `com.sun.tools.javac.code` and `com.sun.tools.javac.util`, and then just using `new TypeMetadata.Annotations(new ListBuffer<>())`. – Johannes Kuhn Aug 26 '23 at 23:34