You’ve in all probability encountered conditions the place you might want to affiliate metadata (knowledge that describes different knowledge) with courses, strategies, and/or different software parts. For instance, your programming group may must establish unfinished courses in a big software. For every unfinished class, the metadata would seemingly embody the title of the developer liable for ending the category and the category’s anticipated completion date.
Earlier than Java 5, feedback had been the one versatile mechanism that Java needed to supply for associating metadata with software parts. Nevertheless, feedback are a poor selection. As a result of the compiler ignores them, feedback are usually not obtainable at runtime. And even when they had been obtainable, the textual content must be parsed to acquire essential knowledge gadgets. With out standardizing how the information gadgets are specified, these knowledge gadgets may show unattainable to parse.
Obtain the supply code for examples on this Java 101 tutorial. Created by Jeff Friesen for InfoWorld.
Java 5 modified the whole lot by introducing annotations, an ordinary mechanism for associating metadata with varied software parts. This mechanism consists of 4 elements:
- An
@interface
mechanism for declaring annotation sorts. - Meta-annotation sorts, which you should utilize to establish the appliance parts to which an annotation kind applies; to establish the lifetime of an annotation (an occasion of an annotation kind); and extra.
- Assist for annotation processing through an extension to the Java Reflection API (to be mentioned in a future article), which you should utilize to find a program’s runtime annotations, and a generalized device for processing annotations.
- Commonplace annotation sorts.
I’ll clarify how one can use these elements as we work our method by means of this text.
Declaring annotation sorts with @interface
You may declare an annotation kind by specifying the @
image instantly adopted by the interface
reserved phrase and an identifier. For instance, Itemizing 1 declares a easy annotation kind that you just may use to annotate thread-safe code.
Itemizing 1: ThreadSafe.java
public @interface ThreadSafe { }
After declaring this annotation kind, prefix the strategies that you just take into account thread-safe with situations of this sort by prepending @
instantly adopted by the kind title to the strategy headers. Itemizing 2 provides a easy instance the place the predominant()
technique is annotated @ThreadSafe
.
Itemizing 2: AnnDemo.java
(model 1)
public class AnnDemo { @ThreadSafe public static void predominant(String[] args) { } }
ThreadSafe
situations provide no metadata aside from the annotation kind title. Nevertheless, you’ll be able to provide metadata by including parts to this sort, the place an aspect is a technique header positioned within the annotation kind’s physique.
In addition to not having code our bodies, parts are topic to the next restrictions:
- The strategy header can’t declare parameters.
- The strategy header can’t present a throws clause.
- The strategy header’s return kind should be a primitive kind (e.g.,
int
),java.lang.String
,java.lang.Class
, an enum, an annotation kind, or an array of one in every of these sorts. No different kind could be specified for the return kind.
As one other instance, Itemizing 3 presents a ToDo
annotation kind with three parts figuring out a specific coding job, specifying the date when the job is to be completed, and naming the coder liable for finishing the job.
Itemizing 3: ToDo.java
(model 1)
public @interface ToDo { int id(); String finishDate(); String coder() default "n/a"; }
Observe that every aspect declares no parameter(s) or throws clause, has a authorized return kind (int
or String
), and terminates with a semicolon. Additionally, the ultimate aspect reveals {that a} default return worth could be specified; this worth is returned when an annotation doesn’t assign a price to the aspect.
Itemizing 4 makes use of ToDo
to annotate an unfinished class technique.
Itemizing 4: AnnDemo.java
(model 2)
public class AnnDemo { public static void predominant(String[] args) { String[] cities = { "New York", "Melbourne", "Beijing", "Moscow", "Paris", "London" }; type(cities); } @ToDo(id = 1000, finishDate = "10/10/2019", coder = "John Doe") static void type(Object[] objects) { } }
Itemizing 4 assigns a metadata merchandise to every aspect; for instance, 1000
is assigned to id
. In contrast to coder
, the id
and finishDate
parts should be specified; in any other case, the compiler will report an error. When coder
isn’t assigned a price, it assumes its default "n/a"
worth.
Java supplies a particular String worth()
aspect that can be utilized to return a comma-separated record of metadata gadgets. Itemizing 5 demonstrates this aspect in a refactored model of ToDo
.
Itemizing 5: ToDo.java
(model 2)
public @interface ToDo { String worth(); }
When worth()
is an annotation kind’s solely aspect, you don’t must specify worth
and the =
project operator when assigning a string to this aspect. Itemizing 6 demonstrates each approaches.
Itemizing 6: AnnDemo.java
(model 3)
public class AnnDemo { public static void predominant(String[] args) { String[] cities = { "New York", "Melbourne", "Beijing", "Moscow", "Paris", "London" }; type(cities); } @ToDo(worth = "1000,10/10/2019,John Doe") static void type(Object[] objects) { } @ToDo("1000,10/10/2019,John Doe") static boolean search(Object[] objects, Object key) { return false; } }
Utilizing meta-annotation sorts — the issue of flexibility
You may annotate sorts (e.g., courses), strategies, native variables, and extra. Nevertheless, this flexibility could be problematic. For instance, you may wish to prohibit ToDo
to strategies solely, however nothing prevents it from getting used to annotate different software parts, as demonstrated in Itemizing 7.
Itemizing 7: AnnDemo.java
(model 4)
@ToDo("1000,10/10/2019,John Doe") public class AnnDemo { public static void predominant(String[] args) { @ToDo(worth = "1000,10/10/2019,John Doe") String[] cities = { "New York", "Melbourne", "Beijing", "Moscow", "Paris", "London" }; type(cities); } @ToDo(worth = "1000,10/10/2019,John Doe") static void type(Object[] objects) { } @ToDo("1000,10/10/2019,John Doe") static boolean search(Object[] objects, Object key) { return false; } }
In Itemizing 7, ToDo
can also be used to annotate the AnnDemo
class and cities
native variable. The presence of those faulty annotations may confuse somebody reviewing your code, and even your individual annotation processing instruments. For the occasions when you might want to slender an annotation kind’s flexibility, Java provides the Goal
annotation kind in its java.lang.annotation
bundle.
Goal
is a meta-annotation kind — an annotation kind whose annotations annotate annotation sorts, versus a non-meta-annotation kind whose annotations annotate software parts, resembling courses and strategies. It identifies the sorts of software parts to which an annotation kind is relevant. These parts are recognized by Goal
’s ElementValue[] worth()
aspect.
java.lang.annotation.ElementType
is an enum whose constants describe software parts. For instance, CONSTRUCTOR
applies to constructors and PARAMETER
applies to parameters. Itemizing 8 refactors Itemizing 5’s ToDo
annotation kind to limit it to strategies solely.
Itemizing 8: ToDo.java
(model 3)
import java.lang.annotation.ElementType; import java.lang.annotation.Goal; @Goal({ElementType.METHOD}) public @interface ToDo { String worth(); }
Given the refactored ToDo
annotation kind, an try to compile Itemizing 7 now ends in the next error message:
AnnDemo.java:1: error: annotation kind not relevant to this sort of declaration @ToDo("1000,10/10/2019,John Doe") ^ AnnDemo.java:6: error: annotation kind not relevant to this sort of declaration @ToDo(worth="1000,10/10/2019,John Doe") ^ 2 errors
Further meta-annotation sorts
Java 5 launched three further meta-annotation sorts, that are discovered within the java.lang.annotation
bundle:
Retention
signifies how lengthy annotations with the annotated kind are to be retained. This sort’s relatedjava.lang.annotation.RetentionPolicy
enum declares constantsCLASS
(compiler information annotations at school file; digital machine doesn’t retain them to avoid wasting reminiscence — default coverage),RUNTIME
(compiler information annotations at school file; digital machine retains them), andSOURCE
(compiler discards annotations).Documented
signifies that situations ofDocumented
-annotated annotations are to be documented byjavadoc
and comparable instruments.Inherited
signifies that an annotation kind is robotically inherited.
Java 8 launched the java.lang.annotation.Repeatable
meta-annotation kind. Repeatable
is used to point that the annotation kind whose declaration it (meta-)annotates is repeatable. In different phrases, you’ll be able to apply a number of annotations from the identical repeatable annotation kind to an software aspect, as demonstrated right here:
@ToDo(worth = "1000,10/10/2019,John Doe") @ToDo(worth = "1001,10/10/2019,Kate Doe") static void type(Object[] objects) { }
This instance assumes that ToDo
has been annotated with the Repeatable
annotation kind.
Processing annotations
Annotations are supposed to be processed; in any other case, there’s no level in having them. Java 5 prolonged the Reflection API that will help you create your individual annotation processing instruments. For instance, Class
declares an Annotation[]
technique that returns an array of
getAnnotations()java.lang.Annotation
situations describing annotations current on the aspect described by the Class
object.
Itemizing 9 presents a easy software that hundreds a category file, interrogates its strategies for ToDo
annotations, and outputs the elements of every discovered annotation.
Itemizing 9: AnnProcDemo.java
import java.lang.mirror.Methodology; public class AnnProcDemo { public static void predominant(String[] args) throws Exception { if (args.size != 1) { System.err.println("utilization: java AnnProcDemo classfile"); return; } Methodology[] strategies = Class.forName(args[0]).getMethods(); for (int i = 0; i < strategies.size; i++) { if (strategies[i].isAnnotationPresent(ToDo.class)) { ToDo todo = strategies[i].getAnnotation(ToDo.class); String[] elements = todo.worth().break up(","); System.out.printf("ID = %spercentn", elements[0]); System.out.printf("End date = %spercentn", elements[1]); System.out.printf("Coder = %spercentnpercentn", elements[2]); } } } }
After verifying that precisely one command-line argument (figuring out a category file) has been specified, predominant()
hundreds the category file through Class.forName()
, invokes getMethods()
to return an array of java.lang.mirror.Methodology
objects figuring out all public
strategies within the class file, and processes these strategies.
Methodology processing begins by invoking Methodology
’s boolean isAnnotationPresent(Class<? extends
technique to find out if the annotation described by
Annotation> annotationClass)ToDo.class
is current on the strategy. In that case, Methodology
’s <T extends Annotation> T getAnnotation(Class<T>
technique is named to acquire the annotation.
annotationClass)
The ToDo
annotations which can be processed are these whose sorts declare a single String worth()
aspect (see Itemizing 5). As a result of this aspect’s string-based metadata is comma-separated, it must be break up into an array of element values. Every of the three element values is then accessed and output.
Compile this supply code (javac AnnProcDemo.java
). Earlier than you’ll be able to run the appliance, you’ll want an appropriate class file with @ToDo
annotations on its public
strategies. For instance, you would modify Itemizing 6’s AnnDemo
supply code to incorporate public
in its type()
and search()
technique headers. You’ll additionally want Itemizing 10’s ToDo
annotation kind, which requires the RUNTIME
retention coverage.
Itemizing 10: ToDo.java
(model 4)
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Goal; @Goal({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface ToDo { String worth(); }
Compile the modified AnnDemo.java
and Itemizing 10, and execute the next command to course of AnnDemo
’s ToDo
annotations:
java AnnProcDemo AnnDemo
If all goes nicely, it’s best to observe the next output:
ID = 1000 End date = 10/10/2019 Coder = John Doe ID = 1000 End date = 10/10/2019 Coder = John Doe
Commonplace annotation sorts
Together with Goal
, Retention
, Documented
, and Inherited
, Java 5 launched java.lang.Deprecated
, java.lang.Override
, and java.lang.SuppressWarnings
. These three annotation sorts are designed for use in a compiler context solely, which is why their retention insurance policies are set to SOURCE
.