javajava-8annotationsjlstype-annotation

Preferred modifier order for annotated methods


According to the JLS (§8.4.3), the preferred order for method modifiers is

Annotation public protected private abstract static final synchronized native strictfp

provided that annotations (if any) are applicable to methods (@Target(METHOD)). On the other hand (§9.7.4), any type annotations for the return types of non-void methods should immediately precede the type.

So if we have a method annotation:

@Target(METHOD)
@interface MethodAnnotation {
}

and a type annotation:

@Target(TYPE_USE)
@interface TypeAnnotation {
}

then the right (as per the preferred coding style) modifier order for a sample method would be

@MethodAnnotation
public static @TypeAnnotation T foo() {
    // ...
}

Now consider we have a "mixed" annotation which applies to both methods and types:

package com.example;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.TYPE_USE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

@Retention(RUNTIME)
@Target({METHOD, TYPE_USE})
@interface MethodOrTypeAnnotation {
        // empty
}

When used on a method, such an annotation will be applied to both the method and its return type. What would the preferred code style be then?

public static @MethodOrTypeAnnotation T foo() {
        // ...
}

Or maybe the below version is better?

@MethodOrTypeAnnotation
public static T foo() {
        // ...
}

Solution

  • Declaring an annotation to be both a type annotation and declaration annotation is bad style. You should avoid creating such annotations.

    The comments give as an example some @Nullable or @NonNull annotations, which are intended to work both with modern tools that process type annotations and with old tools that were written before Java had type annotations. Such type-and-declaration annotations were a temporary measure, intended to be used until the tool supported Java 8, and should not be necessary any longer. The link above gives other examples and how to avoid them.

    That said, if you do have a Frankenstein type-and-declaration annotation, it's best to write it in the location that represents its main meaning or the one being used in this context. In practice, the property is most often a type property and so the annotation should be written together with other type annotations, in front of a type.