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

TYPE_USE annotations on a generic bound are inaccessible/lost

XMLWordPrintable

      FULL PRODUCT VERSION :
      java version "1.8.0_152"
      Java(TM) SE Runtime Environment (build 1.8.0_152-b16)
      Java HotSpot(TM) 64-Bit Server VM (build 25.152-b16, mixed mode)

      ADDITIONAL OS VERSION INFORMATION :
      Linux d0074211 4.13.11 #1 SMP Thu Nov 2 22:32:48 CET 2017 x86_64 GNU/Linux

      EXTRA RELEVANT SYSTEM CONFIGURATION :
      Verified the bug on multiple OSes (Linux, OS X, Windows) and JDK 8.x and 9.x versions

      A DESCRIPTION OF THE PROBLEM :
      Consider this simple class:

      public class SomeClass<T> {
          public <@A1 S extends @A2 T> @A3 S myMethod() { ...}
      }

      @A2 annotation on the bound T is inaccessible via reflection. See below for details.
       
      Assuming myMethod is SomeClass.class.getDeclaredMethod("myMethod"). Type casts removed for readability.

      myMethod.getGenericReturnType().getAnnotations() - returns @A1 (expected)
      myMethod.getGenericReturnType().getBounds()[0].getAnnotations() - returns nothing (no declaration annotation on T)
      myMethod.getAnnotatedReturnType().getAnnotations() - returns @A3 (expected)
      myMethod.getAnnotatedReturnType().getAnnotatedBounds()[0].getAnnotations() - returns @A2

      See https://stackoverflow.com/questions/47175573/how-to-get-type-use-annotations-on-a-generic-bound for a better formatted description, discussion and analysis

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      1. Create a generic class containing a method with an annotated bounded type variable as the return type.
      E.g.
      public class SomeClass<T> {
          public <@A1 S extends @A2 T> @A3 S myMethod() { ...}
      }

      2. Try retrieving the @A2 annotation via reflection:
      Method myMethod = SomeClass.class.getDeclaredMethod("myMethod");
      Annotation[] annotations = myMethod.getGenericReturnType().getBounds()[0].getAnnotations(); // declaration annotation on T
      Annotation[] annotations2 = myMethod.getAnnotatedReturnType().getAnnotatedBounds()[0].getAnnotations(); // type use annotation on T's use as upper(extends) bound


      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      At least one of the annotation arrays from above (annotations and annotations2) should contain the @A2 instance
      ACTUAL -
      Both methods return no annotations

      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      package io.leangen.graphql.jimmy;

      import java.lang.annotation.Annotation;
      import java.lang.annotation.ElementType;
      import java.lang.annotation.Retention;
      import java.lang.annotation.RetentionPolicy;
      import java.lang.annotation.Target;
      import java.lang.reflect.AnnotatedTypeVariable;
      import java.lang.reflect.Method;
      import java.lang.reflect.TypeVariable;

      public class AnnotatedBoundTest {

          @Retention(RetentionPolicy.RUNTIME)
          @Target(ElementType.TYPE_USE)
          @interface A1 {
          }

          @Retention(RetentionPolicy.RUNTIME)
          @Target(ElementType.TYPE_USE)
          @interface A2 {
          }

          @Retention(RetentionPolicy.RUNTIME)
          @Target(ElementType.TYPE_USE)
          @interface A3 {
          }

          public class SomeClass<T> {
              <@A1 S extends @A2 T> @A3 S myMethod() { return null;}
          }


          public static void main(String[] args) throws NoSuchMethodException {
              Method myMethod = SomeClass.class.getDeclaredMethod("myMethod");
              Annotation[] annotations = ((TypeVariable) ((TypeVariable) myMethod.getGenericReturnType()).getBounds()[0]).getAnnotations();
              Annotation[] annotations2 = ((AnnotatedTypeVariable) myMethod.getAnnotatedReturnType()).getAnnotatedBounds()[0].getAnnotations();
              assert annotations.length == 1; // fails, no declaration annotation on T
              assert annotations2.length == 1; // succeeds
          }
      }

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

            Unassigned Unassigned
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            5 Start watching this issue

              Created:
              Updated:
              Resolved: