Bummer! This is just a preview. You need to be signed in with a Basic account to view the entire video.
Starting the Annotation - Declaration and Retention4:15 with Chris Ramacciotti
Setting up the annotation is quite simple. In this video we'll get started by getting a look at the overall structure of the annotation, as well as specifying its retention. The retention is essentially how long it's kept around, from writing our source code to running our application.
There is one more annotation worth mentioning when declaring your custom annotation, and that is the
@Documented annotation. This annotation can be applied to your custom annotations to instruct any documentation-generators (such as Javadoc) to include your annotation in the generated documentation. Though it doesn't affect the functionality of your annotation, it is nice to be able to control whether or not it will appear in your generated API docs, using any number of standard tools.
This annotation can only be applied at the top, declaration-level of an annotation, as the
@Documented annotation is declared with
There's More to the
As you'll see in the coming videos, we will use reflection to analyze the presence of our
@Doc annotation on classes and methods. In order to use reflection during this analysis, the annotation must be declared with
However, there is actually a way for to use
RetentionPolicy.SOURCE and still have access to annotations for processing, using a method other than reflection. If you want to check out that approach, I’ve created a sample project for you. Let's consider the following scenario.
Sometimes developers find themselves writing a bunch of standard code. For example, a class containing a bunch of fields, each of which has getters & setters. The code for this follows a simple set of rules based on the field names and types. Any code that follows a set of reasonably standard rules and has consistent structure is commonly called “boilerplate code”.
In order to leverage
SOURCE-level annotations, you must write what's called an annotation processor, typically by extending
javax.annotation.processing.AbstractProcessor, providing an implementation of the
process method. To run the processor, you'll use the javac console command and include the -processor option.
The project I’ve provided allows you to create a simple class containing a list of annotated fields. The included annotation processor reads the annotations and generates a full Java class, including all fields, getters and setters. In this example, the final Java class contains 40 lines of code, but it takes only 18 lines of annotated code to generate it. That’s a savings of 22 lines of code. Now imagine you have 20 classes like this to generate. You just saved yourself 440 lines of code. Go Java!
To use this sample, download and extract the ZIP file. Then in a console, change directories into the java-annotations-processor directory, and run the following commands:
Compile all Java files in the boilerplate directory
javac -d out -cp src src/com/teamtreehouse/boilerplate/**
Run the annotation processor on the PersonStub.java file
javac -cp out -processor com.teamtreehouse.boilerplate.BoilerplateGenerator src/com/teamtreehouse/sample/PersonStub.java
The result of the second command will be a Person.java file that contains the full
Person class. Compare this generated code with the original PersonStub.java code, and you’ll see the difference.
In general, one of the most common uses of source-level annotations - that is, using
RetentionPolicy.SOURCE - is to generate other code files. This is certainly not the only use, but it sure is a powerful one!
Okay, we're ready to begin.
Let's now switch to the doc annotation.
The first thing you'll notice is that the annotation is declared with at interface.
It's not a traditional interface that would need to be leveraged by using
the implements keyword, this one is different.
The use of this at sign here tells the Java compiler that
this will be an annotation.
In general, we'll want to do three things when we declare an interface in Java.
Number one is declare the interface itself, I have done this for you.
Number two, specify what are called retention and targets.
And number three, add elements or attributes.
Now these first two steps involve adding other annotations to our own annotation.
This might seem a little cyclic at first, but you'll see that these new annotations
are part of the Java annotation framework itself.
The first thing we'll do is specify what's called the retention of this annotation.
That is, how long will the doc annotation be retained in Java files that use this?
In order to add this, we will use the retention annotation.
Now in parentheses here, we have three choices.
Number one, RetentionPolicy.SOURCE, number 2 two RetentionPolicy.CLASS,
or number three, RetentionPolicy.Runtime.
If we choose source,
we're telling the Java compiler to throw away the annotation upon compiling.
This is how the override and suppress warnings annotations are defined.
The compiler uses them to help it in compiling, and then throws them away.
We might want to choose it if it's only important for
compiler messages, but the annotations themselves wouldn't be available during
run time to analyze their presence, so we won't be using source.
If we choose class, we're telling the compiler to retain the annotations in
the byte code that the compiler produces.
But with this option,
the annotations are not loaded into the JVM while running the program.
This means that, again, they're not available for analysis at run time.
We'll pass up the CLASS option as well.
Finally we can choose runtime, which is exactly what it sounds like.
It means they're included in the compiled code and
made available to the JVM upon running our application.
We'll pick runtime because it will allow us to examine the MathUtils class for
the presence of annotations,
using an approach called reflection, more on reflection later.
Let's add the runtime retention policy now.
So in parentheses of the retention annotation,
we will add RetentionPolicy.RUNTIME in all caps.
Now, in order to use both the retention annotation and reference the retention
policy class, we'll need to add import statements for both of those.
So import java.lang.annotation.retention.
Also, import java.lang.annotation.retentionpolicy.
As a side note,
the deprecated annotation is defined using the runtime as its retention policy.
Also, I want to point out that when you put things in parentheses while adding
annotations, kind of like we did with suppressed warnings in a previous video,
or like we're doing here with the retention policy.runtime,
we're actually passing a value to what's called an element of the annotation.
To drive that point home, we could type the actual name of the element,
which in this case is value.
If there were more elements in the annotation we'd create a comma separated
list of name value pairs, according to how the annotation is defined.
For example, we could write something equal stuff comma,
something else equals things, if the annotation itself
happened to have elements named something or something else.
This annotation does not, so I'll go ahead and remove and remove those.
Java does allow you to leave out the name of an element,
if the element's name is exactly value.
So when we leave out this value equals right here,
we're actually using shorthand.
We'll continue to use this shortened syntax, but
now you know what it really means.
You need to sign up for Treehouse in order to download course files.Sign up