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

@SupportedAnnotationTypes.value awkward & unsafe; prefer Class[]

XMLWordPrintable

    • Icon: Enhancement Enhancement
    • Resolution: Won't Fix
    • Icon: P5 P5
    • None
    • 6u10
    • core-libs

      A DESCRIPTION OF THE REQUEST :
      Writers of annotation processors (assignable to AbstractProcessor) are encouraged to use @SupportedAnnotationTypes, supposedly because this is easier than implementing getSupportedAnnotationTypes.

      In fact it is not a very good idea to do this. Most processors will have a fixed list of annotation types they support, often just one; wildcards can be expected to be rare. ("*" is needed for processors which don't actually look for annotations, but it seems very poor style to specify "my.package.*" because you then claim to be handling any future annotations added to that package, perhaps by a third party. This produces the same class of problems as wildcard imports. More likely you know in advance what the interesting annotations are, so just list them.)

      But specifying a list of annotation type names as String's, as @SAT requires, is bad for the usual reasons hardcoded string literals are bad:

      1. It is easy to mistype one of the identifiers, or get confused about '$' vs. '.' for nested types, etc.

      2. IDEs and assorted refactoring tools will in general not recognize the value as corresponding to the annotation type. So "find usages" queries, rename refactorings, etc. can easily break the annotation processor.

      Such bugs are of course easy enough to find & fix, but it puts an unnecessary drag on development.

      Suggest the following modified signature:

      @Documented
      @Target(TYPE)
      @Retention(RUNTIME)
      public @interface SupportedAnnotationTypes {
        String[] value() default {};
        Class<? extends Annotation>[] types() default {};
      }

      This would provide a readable, type-safe, code-completion-and-refactoring-friendly alternative notation:

      @SupportedAnnotationTypes(types=MyAnnotation.class)
      public class MyProcessor extends AbstractProcessor {...}

      AbstractProcessor would collect the literals given in value(), add in any types() (mapped using getCanonicalName()), and return the resulting set (warning if empty).


      Another option would be a modest language change, useful in other contexts as well: treat <identifier>.class.get{,Simple,Canonical}Name() as a compile-time string constant. Without any changes to 269, you could then write:

      @SupportedAnnotationTypes(MyAnnotation.class.getCanonicalName())
      public class MyProcessor extends AbstractProcessor {...}

      I guess this would be material for Project Coin.

      JUSTIFICATION :
      Improves safety and readability of code.


      CUSTOMER SUBMITTED WORKAROUND :
          public @Override Set<String> getSupportedAnnotationTypes() {
              return new HashSet<String>(Arrays.asList(
                  MyFirstAnnotation.class.getCanonicalName(),
                  MySecondAnnotation.class.getCanonicalName()
              ));
          }

      Works, just verbose. I will change all of our processors to use this style.

            darcy Joe Darcy
            ndcosta Nelson Dcosta (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: