Does this have a purpose static @NotNull @Other My.@NotNull @Other Builder createBuilder()
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
public class A {
static class My {
static class Builder {
public My build() {
return new My(); } } }
@Target({ElementType.METHOD, ElementType.TYPE_USE})
public @interface NotNull { }
@Target({ElementType.METHOD, ElementType.TYPE_USE})
public @interface Other { }
public static @NotNull @Other My.@NotNull @Other Builder createBuilder() {
return new My.Builder();
}
}
Annotations are used to provide supplemental information about a program. Annotations start with '@'. Annotations do not change the action of a compiled program. Annotations help to associate metadata (information) to the program elements i.e. instance variables, constructors, methods, classes, etc.
Annotation Type Target. Indicates the contexts in which an annotation type is applicable. The declaration contexts and type contexts in which an annotation type may be applicable are specified in JLS 9.6. 4.1, and denoted in source code by enum constants of java.
Annotation is defined like a ordinary Java interface, but with an '@' preceding the interface keyword (i.e., @interface ). You can declare methods inside an annotation definition (just like declaring abstract method inside an interface). These methods are called elements instead.
Annotations don't execute; they're notes or markers that are read by various tools. Some are read by your compiler, like @Override ; others are embedded in the class files and read by tools like Hibernate at runtime. But they don't do anything themselves.
The main reason to use such a construct would be backward compatibility.
Prior to Java 8, there were no type annotations, so method annotations were often used to actually described the return type of a method like
@Target(ElementType.METHOD)
public @interface NotNull { }
@Target(ElementType.METHOD)
public @interface Other { }
public static @NotNull @Other My.Builder createBuilder() {
return new My.Builder();
}
Starting with Java 8, you can annotate the return type itself and that’s what you normally would do. But to support old tools still looking for method annotations, you can keep the @Target
METHOD
. For return types consisting of a simple name, the code location for method annotations and return type annotations is the same, so you can create a method annotation and a return type annotation at the same time with a single occurrence, i.e.
@MethodAndTypeAnnotation ReturnType method() …
However, for qualified names, the syntax is different, as type annotation must be placed immediately prior to the simple name of the annotated element, i.e.
@Target(ElementType.TYPE_USE)
public @interface NotNull { }
@Target(ElementType.TYPE_USE)
public @interface Other { }
public static My.@NotNull @Other Builder createBuilder() {
return new My.Builder();
}
For a pure type annotation using public static @NotNull @Other My.Builder createBuilder()
would cause a compiler error, as it would be an attempt to annotate My
which only serves as a qualifier here, not an actual type use. Note that if Builder
was an inner class rather than a nested class (i.e. not static
), it would be legal to annotate the outer type, though unlikely to be desired.
So in your case
@Target({ElementType.METHOD, ElementType.TYPE_USE})
public @interface NotNull { }
@Target({ElementType.METHOD, ElementType.TYPE_USE})
public @interface Other { }
// method annotation type annotation
public static @NotNull @Other My.@NotNull @Other Builder createBuilder() {
return new My.Builder();
}
both occurrences are required to annotate the method and the return type. As said, if the Builder
was an inner class, the first occurrence would be legal to annotate the outer type and it would annotate it whether you want or not.
So in general, it’s not recommended to mix the “type use” annotation scope with others but to update code processing tools still requiring method or field annotations for tasks that are actually a type annotation’s job.
As said, for simple names you can annotate the method and return type at once, which also works for nested types when you use an import
statement. But this requires the top level class to be in a package:
package example;
import example.A.My.Builder;
public class A {
static class My {
static class Builder {
public My build() {
return new My(); } } }
@Target({ElementType.METHOD, ElementType.TYPE_USE})
public @interface NotNull { }
@Target({ElementType.METHOD, ElementType.TYPE_USE})
public @interface Other { }
public static @NotNull @Other Builder createBuilder() {
return new My.Builder();
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With