Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8349716

IllegalAccessError when Proxy methods return object of a package-private type

XMLWordPrintable

    • Cause Known
    • generic
    • generic

      ADDITIONAL SYSTEM INFORMATION :
      Microsoft Windows 10 Version 22H2 (OS Build 19045.5371)

      java version "23.0.2" 2025-01-21
      Java(TM) SE Runtime Environment (build 23.0.2+7-58)
      Java HotSpot(TM) 64-Bit Server VM (build 23.0.2+7-58, mixed mode, sharing)

      Also observed with OpenJDK Runtime Environment Temurin-21.0.5+11 (build 21.0.5+11-LTS)


      A DESCRIPTION OF THE PROBLEM :
      When creating a method handle for a annotation inside of a package visible annotation with a Lookup object that has access to the package, the creation of the MethodHandle succeeds, but calling MethodHandle,invoke fails with an IllegalAccessError.
      This happens only when the annotation is "real" annotation uses a target of the invocation; if the interface is implemented by a class it works as expected.
      This works as expected with OpenJ9

      Developer (liach) note:
      When creating a Proxy that has a method that returns objects of package-private types, and that particular method is called and returns non-null, the method throws an `IllegalAccessError`.
      The culprit is the checkcast in codeUnwrapValue, which does not perform class or interface resolution when the value is `null`. This has been in place since the initial load of OpenJDK.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Compile and run the source code


      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      Code runs without exception
      ACTUAL -
      Exception in thread "main" java.lang.IllegalAccessError: failed to access class Reflection$Y from class jdk.proxy2.$Proxy1 (Reflection$Y is in unnamed module of loader 'app'
      ; jdk.proxy2.$Proxy1 is in module jdk.proxy2 of loader 'app')
              at jdk.proxy2/jdk.proxy2.$Proxy1.value(Unknown Source)
              at Reflection.main(Reflection.java:39)


      ---------- BEGIN SOURCE ----------
      import java.lang.annotation.Annotation;
      import java.lang.annotation.Repeatable;
      import java.lang.annotation.Retention;
      import java.lang.annotation.RetentionPolicy;
      import java.lang.invoke.MethodHandle;
      import java.lang.invoke.MethodHandles;
      import java.lang.invoke.MethodHandles.Lookup;
      import java.lang.invoke.MethodType;
      import java.lang.reflect.AnnotatedElement;
      import java.lang.reflect.InvocationHandler;
      import java.lang.reflect.Method;
      import java.lang.reflect.Modifier;
      import java.lang.reflect.ParameterizedType;
      import java.lang.reflect.Proxy;
      import java.lang.reflect.Type;
      import java.util.Arrays;
      import java.util.stream.Stream;

      final class Reflection {

              @Reflection.Y.Y1({})
              private Reflection() {
              }

              @Retention(RetentionPolicy.RUNTIME)
              @interface Y {
                      String value();

                      @Retention(RetentionPolicy.RUNTIME)
                      @interface Y1 {
                              Y[] value();
                      }
              }

              public static void main(String... args) throws Throwable {
                      MethodHandle methodHandle = MethodHandles.lookup().findVirtual(Reflection.Y.Y1.class, "value", MethodType.methodType(Y[].class));
                      Reflection.Y.Y1 y1 = Reflection.class.getDeclaredConstructor().getAnnotation(Reflection.Y.Y1.class);

                      methodHandle.invoke(y1);
              }
      }

      ---------- END SOURCE ----------

            liach Chen Liang
            webbuggrp Webbug Group
            Votes:
            1 Vote for this issue
            Watchers:
            5 Start watching this issue

              Created:
              Updated: