Learn Java and Programming through articles, code examples, and tutorials for developers of all levels.

  • online courses
  • certification
  • free resources

10 Spring Framework Annotations Java Developer should learn - Example Tutorial

10+ essential spring core annotations for java developers, 1. @configuration, 2. @componentscan.

10 Essential Spring Core Annotations Every Java Developer Should Learn

8. @Qualifier

Top 10 Spring Framework Annotations for Java Developers

much needed information

Feel free to comment, ask questions if you have any doubt.


5 Annotations Every Java Developer Should Know

In this article, we will take a look at 5 of the annotations supported by all java compilers and take a look at their intended uses..

Justin Albano user avatar

Join the DZone community and get the full member experience.

Since their inception in Java Development Kit (JDK) 5, annotations have become an indispensable part of the Java ecosystem. While there are countless custom annotations developed for use by Java frameworks (such as  @Autowired  for Spring ), there are a few annotations recognized by the compiler that are of supreme importance. In this article, we will take a look at 5 of the annotations supported by all Java compilers and take a look at their intended uses. Along the way, we will explore the rationale behind their inception, some idiosyncrasies that surround their use, and some examples of their proper application. Although some of these annotations are more common than others, each should be internalized by non-beginner Java developers. To start off, we will delve into one of the most commonly used annotations in Java:  @Override .

The ability to override the implementation of a method, or provide an implementation for an abstract method, is at the core of any Object-Oriented (OO) language. Being that Java is an OO language and features many of the common OO abstraction mechanisms, a non-final method defined in a non-final superclass or any method in an interface (interface methods cannot be final) can be overridden by a subclass. Although overriding a method appears to be straightforward at first, there are many subtle bugs that can be introduced when overriding is performed incorrectly. For example, it is a common mistake to override the  Object#equals   method with a single parameter of the type of the overriding class:

Being that all classes implicitly inherit from the  Object  class, the intent of our  Foo  class is to the override the  Object#equals  method so that  Foo  can be tested for equality against any other object in Java. While our intent is correct, our implementation is not . In fact, our implementation does not override the  Object#equals  method at all. Instead, we provide an overload of the method: rather than substituting the implementation of the  equals  method provided by the  Object  class, we instead provide a second method that accepts  Foo  object specifically, rather than an  Object  object. Our mistake can be illustrated using the trivial implementation that returns  true   for all equality checks but is never called when the supplied object is treated as an  Object  (which Java will do, such as in the Java Collections Framework, JCF):

This is a very subtle, but common error that could be caught by the compiler. It was our intent to override the  Object#equals  method, but because we specified a parameter of type  Foo , rather than type Object , we in fact provided overloaded the  Object#equals  method, rather than overriding it. In order to catch mistakes of this kind, the  @Override  annotation was introduced, which instructs the compiler to check if an override was actually performed. If a valid override was not performed, an error is thrown. Thus, we can update our  Foo   class to resemble the following:

If we try to compile this class, we now receive the following error:

In essence, we have transformed our implicit assumption that we have overridden a method into an explicit verification by the compiler. In the event that our intent was incorrectly implemented, the Java compiler will emit an error, not allowing our code with our incorrect implementation to successfully compile. In general, the Java compiler will emit an error for a method annotated with  @Override   if either of the following conditions is not satisfied (quoted from the Override annotation documentation ):

Therefore, we can also use this annotation to ensure that a subclass method actually overrides a non-final concrete method or abstract method in a superclass as well:

The  @Override   annotation is not relegated to just concrete or abstract methods in a superclass, but can also be used to ensure that methods of an interface are overridden as well ( since JDK 6 ):

In general, any method that overrides a non-final concrete class method, an abstract superclass method, or an interface method can be annotated with  @Override . For more information on valid overrides, see the Overriding and Hiding documentation and section of the Java Language Specification (JLS) .


With the introduction of lambda expressions in JDK 8, functional interfaces have become much more prevalent in Java. These special types of interfaces can be substituted with lambda expressions, method references, or constructor references. According to the  @FunctionalInterface  documentation , a functional interface is defined as follows:

A functional interface has exactly one abstract method. Since default methods have an implementation, they are not abstract.

For example, the following interfaces are considered functional interfaces:

Thus, each of the following can be substituted with a lambda expression as follows:

It is important to note that abstract classes, even if they contain only one abstract method, are not  functional interfaces. For more information on this decision, see  Allow lambdas to implement abstract classes written by Brian Goetz, chief Java Language Architect. Similar to the  @Override  annotation, the Java compiler provides the  @FunctionalInterface  annotation to ensure that an interface is indeed a functional interface. For example, we could add this annotation to the interfaces we created above:

If we were to mistakenly define our interfaces as non-functional interfaces and annotated the mistaken interface with the @FunctionalInterface , the Java compiler would emit an error. For example, we could define the following annotated, non-functional interface:

If we tried to compile this interface, we would receive the following error:

Using this annotation, we can ensure that we do not mistakenly create a non-functional interface that we intended to be used as a functional interface. It is important to note that interfaces can be used as the functional interfaces (can be substituted as lambdas, method references, and constructor references) even when the  @FunctionalInterface  annotation is not present, as we saw in our previous example. This is analogous to the  @Override  annotation, where a method can be overridden, even if it does not include the  @Override  annotation. In both cases, the annotation is an optional technique for allowing the compiler to enforce our intent.

For more information on the  @FunctionalInterface  annotation, see the  @FunctionalInterface  documentation and section of the JLS .


Warnings are an important part of any compiler, providing a developer with feedback about possibly dangerous behavior or possible errors that may arise in future versions of the compiler. For example, using generic types in Java without their associated formal generic parameter (called raw types ) causes a warning, as does the use of deprecated code (see the  @Deprecated  section below). While these warnings are important, they may not always be applicable or even correct. For example, there may be instances where a warning is emitted for an unsafe type conversion, but based on the context in which it is used, it can be guaranteed to be safe. 

In order to ignore specific warnings in certain contexts, the  @SuppressWarnings  annotation was introduced in JDK 5. This annotation accepts 1 or more string arguments that represent the name of the warnings to ignore. Although the names of these warnings generally vary between compiler implementation, there are 3 warnings that are standard in the Java language (and hence are common among all Java compiler implementations):

In order to ignore a specific warning, the  @SuppressedWarning   annotation, along with 1 or more names of suppressed warnings (supplied in the form of a string array), can be added to the context in which the warning would occur:

The  @SuppressWarnings   annotation can be used on any of the following:

In general, the  @SuppressWarnings  annotation should be applied to the most immediate scope of the warning. For example, if a warning should be ignored for a local variable within a method, the  @SuppressWarnings   annotation should be applied to the local variable, rather than the method or the class that contains the local variable:


Varargs can be a useful technique in Java, but they can also cause some serious issues when paired with generic arguments. Since generics are non-reified in Java, the actual (implementation) type of a variable with a generic type cannot be determined at runtime. Since this determination cannot be made, it is possible for a variable to store a reference to a type that is not its actual type, as seen in the following snippet (derived from Java Generics FAQs ):

After the assignment of  ln  to  ls , there exists a variable  ls   in the heap that has a type of  List<String>  but stores a reference to a value that is actually of type  List<Number> . This invalid reference is known as heap pollution . Since this error cannot be determined until runtime, it manifests itself as a warning at compile time and a  ClassCastException  at runtime. This issue can be exacerbated when generic arguments are combined with varargs:

In this case, the Java compiler internally creates an array at the call site to store the variable number of arguments, but the type of  T  is not reified and is therefore lost at runtime. In essence, the parameter to  doSomething  is actually of type Object[] . This can cause serious issues if the runtime type of  T   is relied upon, as in the following snippet:

If executed, this snippet will result in a ClassCastException , because the first  Number  argument passed at the call site cannot be converted to a  String   (similar to the  ClassCastException  thrown in the standalone heap pollution example. In general, there may be cases where the compiler does not have enough information to properly determine the exact type of a generic vararg parameter, which can result in heap pollution. This pollution can be propagated by allowing the internal varargs array to escape from a method, as in the following example from pp. 147 of Effective Java, 3rd Edition :

In some cases, we know that a method is actually type safe and will not cause heap pollution. If this determination can be made with assurance, we can annotate the method with the  @SafeVarargs  annotation, which suppresses warnings related to possible heap pollution. This begs the question, though: When is a generic vararg method considered type safe? Josh Bloch provides a sound answer on pp. 147 of  Effective Java, 3rd Edition , based on the interaction of a method with the internally created array used to store its varargs:

If the method doesn’t store anything into the array (which would overwrite the parameters) and doesn’t allow a reference to the array to escape (which would enable untrusted code to access the array), then it’s safe. In other words, if the varargs parameter array is used only to transmit a variable number of arguments from the caller to the method—which is, after all, the purpose of varargs—then the method is safe.

Thus, if we created the following method (from pp. 149 Ibid.), we can soundly annotate our method with the  @SafeVarags   annotation:

For more information on the  @SafeVarargs  annotation, see the @SafeVarargs documentation , JLS section , and Item 32 from  Effective Java, 3rd Edition .


When developing code, there may be times when code becomes out-of-date and should no longer be used. In these cases, there is usually a replacement that is better suited for the task at hand and while existing calls to the out-dated code may remain, all new calls should use the replacement method. This out-of-date code is called deprecated code. In some pressing cases, deprecated code may be slated for removal and should be immediately converted to the replacement code before a future version of a framework or library removes the deprecated code from its code base.

In order to support the documentation of deprecated code, Java includes the  @Deprecated  annotation, which marks some constructor, field, local variable, method, package, module, parameter, or type as being deprecated. If this deprecated element (constructor, field, local variable, etc.) is used, the compiler will emit a warning. For example, we can create a deprecated class and use it as follows:

If we compile this code (in a file called Main.java ), we receive the following warning:

In general, a warning will be thrown whenever an element annotated with  @Deprecated   is used, except in the following five circumstances:

As previously mentioned, there are some cases when a deprecated element is slated for removal and calling code should immediately remove the deprecated element (called terminally deprecated code). In this case, the  @Deprecated   annotation can be supplied with a  forRemoval   argument as follows:

Using this terminally deprecated code now results in a more imposing set of warnings:

Terminally deprecated warnings are always emitted, save for the same exceptions described for the standard  @Deprcated  annotation. We can also add documentation to the  @Deprecated   annotation by supplying a  since   argument to the annotation:

Deprecated elements can be further documented using the  @deprecated   JavaDoc element (note the lowercase d ), as seen in the following snippet:

The JavaDoc tool will then produce the following documentation:

Image title

For more information on the  @Deprecated  annotation, see the @Deprecated documentation and JLS section .

Annotations have been an indispensable part of Java since their introduction in JDK 5. While some are more popular than others, there are 5 annotations that any developer above the novice level should understand: @Override , @FunctionalInterface , @SuppressWarnings , @SafeVarargs , and @Deprecated . While each has its own unique purpose, the aggregation of these annotations make a Java application much more readable and allow the compiler to enforce some otherwise implicit assumptions about our code. As the Java language continues to grow, these tried-and-true annotations will likely see many more years of service and help to ensure that many more applications behave as their developers intended.

Opinions expressed by DZone contributors are their own.

Popular on DZone

Partner Resources


Let's be friends:

Java Hungry

Java developers tutorials and coding.

Top 10 most frequently used Annotation example

java annotation exmaple

About The Author Subham Mittal has worked in Oracle for 3 years. Enjoyed this post? Never miss out on future posts by subscribing JavaHungry

Get new posts by email:


An Introduction to Annotations and Annotation Processing in Java

An annotation is a construct associated with Java source code elements such as classes, methods, and variables. Annotations provide information to a program at compile time or at runtime based on which the program can take further action. An annotation processor processes these annotations at compile time or runtime to provide functionality such as code generation, error checking, etc.

The java.lang package provides some core annotations and also gives us the capability to create our custom annotations that can be processed with annotation processors.

In this article, we will discuss the topic of annotations and demonstrate the power of annotation processing with a real-world example.

Example Code

Annotation basics.

An annotation is preceded by the @ symbol. Some common examples of annotations are @Override and @SuppressWarnings . These are built-in annotations provided by Java through the java.lang package. We can further extend the core functionality to provide our custom annotations.

An annotation by itself does not perform any action. It simply provides information that can be used at compile time or runtime to perform further processing.

Let’s look at the @Override annotation as an example:

We use the @Override annotation to mark a method that exists in a parent class, but that we want to override in a child class. The above program throws an error during compile time because the getname() method in ChildClass is annotated with @Override even though it doesn’t override a method from ParentClass (because there is no getname() method in ParentClass ).

By adding the @Override annotation in ChildClass , the compiler can enforce the rule that the overriding method in the child class should have the same case-sensitive name as that in the parent class, and so the program would throw an error at compile time, thereby catching an error which could have gone undetected even at runtime.

Standard Annotations

Below are some of the most common annotations available to us. These are standard annotations that Java provides as part of the java.lang package. To see their full effect it would be best to run the code snippets from the command line since most IDEs provide their custom options that alter warning levels.


We can use the @SuppressWarnings annotation to indicate that warnings on code compilation should be ignored. We may want to suppress warnings that clutter up the build output. @SuppressWarnings("unchecked") , for example, suppresses warnings associated with raw types.

Let’s look at an example where we might want to use @SuppressWarnings :

If we run this program from the command-line using the compiler switch -Xlint:unchecked to receive the full warning list, we get the following message:

The above code-block is an example of legacy Java code (before Java 5), where we could have collections in which we could accidentally store mixed types of objects. To introduce compile time error checking generics were introduced. So to get this legacy code to compile without error we would change:

If we had a large legacy code base, we wouldn’t want to go in and make lots of code changes since it would mean a lot of QA regression testing. So we might want to add the @SuppressWarning annotation to the class so that the logs are not cluttered up with redundant warning messages. We would add the code as below:

Now if we compile the program, the console is free of warnings.


We can use the @Deprecated annotation to mark that a method or type has been replaced with newer functionality.

IDEs make use of annotation processing to throw a warning at compile time, usually indicating the deprecated method with a strike-through to tell the developer that they shouldn’t use this method or type anymore.

The following class declares a deprecated method:

The attribute since in the annotation tells us in which version the element was deprecated, and forRemoval indicates if the element is going to be removed in the next version.

Now, calling the legacy method as below will trigger a compile time warning indicating that the method call needs to be replaced:

We already had a look at the @Override annotation above. We can use it to indicate that a method will be overriding the method with the same signature in a parent class. It is used to throw compile time errors in cases such as typos in letter-casing as in this code example:

We intended to override the getEmployeeStatus() method but we misspelled the method name. This can lead to serious bugs. The program above would compile and run without issue without catching that bug.

If we add the annotation @Override to the getemployeeStatus() method, we get a compile time error, which causes a compile error and forces us to correct the typo right away:


The @FunctionalInterface annotation is used to indicate that an interface cannot have more than one abstract method. The compiler throws an error in case there is more than one abstract method. Functional interfaces were introduced in Java 8, to implement Lambda expressions and to ensure that they didn’t make use of more than one method.

Even without the @FunctionalInterface annotation, the compiler will throw an error if you include more than one abstract method in the interface. So why do we need @FunctionalInterface if it is not mandatory?

Let us take the example of the code below:

If we add another method printString2() to the Print interface, the compiler or the IDE will throw an error and this will be obvious right away.

Now, what if the Print interface was in a separate module, and there was no @FunctionalInterface annotation? The developers of that other module could easily add another function to the interface and break your code. Further, now we have to figure out which of the two is the right function in our case. By adding the @FunctionalInterface annotation we get an immediate warning in the IDE, such as this:

So it is good practice to always include the @FunctionalInterface if the interface should be usable as a Lambda.


The varargs functionality allows the creation of methods with variable arguments. Before Java 5, the only option to create methods with optional parameters was to create multiple methods, each with a different number of parameters. Varargs allows us to create a single method to handle optional parameters with syntax as below:

However, warnings are thrown when generics are used in the arguments. @SafeVarargs allows for suppression of these warnings:

In the above code, printString() and printStringVarargs() achieve the same result. Compiling the code, however, produces a warning for printStringSafeVarargs() since it used generics:

By adding the SafeVarargs annotation as below, we can get rid of the warning:

Custom Annotations

These are annotations that are custom-created to serve a particular purpose. We can create them ourselves. We can use custom annotations to

An example of a custom annotation would be this @Company annotation:

When creating multiple instances of the CustomAnnotatedEmployee class, all instances would contain the same company name and city , so wouldn’t need to add that information to the constructor anymore.

To create a custom annotation we need to declare it with the @interface keyword:

To specify information about the scope of the annotation and the area it targets, such as compile time or runtime, we need to add meta annotations to the custom annotation.

For example, to specify that the annotation applies to classes only, we need to add @Target(ElementType.TYPE) , which specifies that this annotation only applies to classes, and @Retention(RetentionPolicy.RUNTIME) , which specifies that this annotation must be available at runtime. We will discuss further details about meta annotations once we get this basic example running.

With the meta annotations, our annotation looks like this:

Next, we need to add the fields to the custom annotation. In this case, we need name and city . So we add it as below:

Putting it all together, we can create a CustomAnnotatedEmployee class and apply the annotation to it as below:

Now we can create a test class to read the @Company annotation at runtime:

This would give the output below:

So by introspecting the annotation at runtime we can access some common information of all employees and avoid a lot of repetition if we had to construct a lot of objects.

Meta Annotations

Meta annotations are annotations applied to other annotations that provide information about the annotation to the compiler or the runtime environment.

Meta annotations can answer the following questions about an annotation:

By default, an annotation is not inherited from a parent class to a child class. Applying the @Inherited meta annotation to an annotation allows it to be inherited:

Since CustomAnnotatedEmployee has the @Company annotation and CustomAnnotatedManager inherits from it, the CustomAnnotatedManager class does not need to include it.

Now if we run the test for the Manager class, we still get access to the annotation information, even though the Manager class does not have the annotation:


@Documented ensures that custom annotations show up in the JavaDocs.

Normally, when we run JavaDoc on the class CustomAnnotatedManager the annotation information would not show up in the documentation. But when we use the @Documented annotation, it will:


@Repeatable allows multiple repeating custom annotations on a method, class, or field. To use the @Repeatable annotation we need to wrap the annotation in a container class which refers to it as an array:

We declare our main class as below:

If we run a test on it as below:

We get the following output which displays the value of multiple @RepeatableCompany annotations:

@Target specifies on which elements the annotation can be used, for example in the above example the annotation @Company was defined only for TYPE and so it could only be applied to a class.

Let’s see what happens if we apply the @Company annotation to a method:

If we applied the @Company annotation to the method getEmployeeStatus() as above, we get a compiler error stating: '@Company' not applicable to method.

The various self-explanatory target types are:

@Retention specifies when the annotation is discarded.

SOURCE - The annotation is used at compile time and discarded at runtime.

CLASS - The annotation is stored in the class file at compile time and discarded at run time.

RUNTIME - The annotation is retained at runtime.

If we needed an annotation to only provide error checking at compile time as @Override does, we would use SOURCE . If we need an annotation to provide functionality at runtime such as @Test in Junit we would use RUNTIME . To see a real example, create the following annotations in 3 separate files:

Now create a class that uses all 3 annotations:

To verify that only the runtime annotation is available at runtime, run a test as follows:

The output would be as follows:

So we verified that only the RUNTIME annotation gets processed at runtime.

Annotation Categories

Annotation categories distinguish annotations based on the number of parameters that we pass into them. By categorizing annotations as parameter-less, single value, or multi-value, we can more easily think and talk about annotations.

Marker Annotations

Marker annotations do not contain any members or data. We can use the isAnnotationPresent() method at runtime to determine the presence or absence of a marker annotation and make decisions based on the presence of the annotation.

For example, if our company had several clients with different data transfer mechanisms, we could annotate the class with an annotation indicating the method of data transfer as below:

The client class could use the annotation as below:

We can process the annotation as follows:

Based on whether the @CSV annotation exists or not, we can decide whether to write out the information to CSV or an Excel file. The above program would produce this output:

Single-Value Annotations

Single-value annotations contain only one member and the parameter is the value of the member. The single member has to be named value .

Let’s create a SingleValueAnnotationCompany annotation that uses only the value field for the name, as below:

Create a class that uses the annotation as below:

Run a test as below:

The single value ‘XYZ’ overrides the default annotation value and the output is as below:

Full Annotations

They consist of multiple name value pairs. For example Company(name="ABC", city="XYZ") . Considering our original Company example:

Let’s create the MultiValueAnnotatedEmployee class as below. Specify the parameters and values as below. The default values will be overwritten.

The output is as below, and has overridden the default annotation values:

Building a Real-World Annotation Processor

For our real-world annotation processor example, we are going to do a simple simulation of the annotation @Test in JUnit. By marking our functions with the @Test annotation we can determine at runtime which of the methods in a test class need to be run as tests.

We first create the annotation as a marker annotation for methods:

Next, we create a class AnnotatedMethods , to which we will apply the @Test annotations to the method test1() . This will enable the method to be executed at runtime. The method test2() does not have an annotation, and should not be executed at runtime.

Now we create the test to run the AnnotatedMethods class:

By calling getDeclaredMethods() , we’re getting the methods of our AnnotatedMethods class. Then, we’re iterating through the methods and checking each method if it is annotated with the @Test annotation. Finally, we perform a runtime invocation of the methods that were identified as being annotated with @Test .

We want to verify the test1() method will run since it is annotated with @Test , and test2() will not run since it is not annotated with @Test .

The output is:

So we verified that test2() , which did not have the @Test annotation, did not have its output printed.

We did an overview of annotations, followed by a simple real-world example of annotation processing.

We can further use the power of annotation processing to perform more complex automated tasks such as creating builder source files for a set of POJOs at compile time. A builder is a design pattern in Java that is used to provide a better alternative to constructors when there is a large number of parameters involved or there is a need for multiple constructors with optional parameters. If we had a few dozen POJOs, the code generation capabilities of the annotation processor would save us a lot of time by creating the corresponding builder files at compile time.

By fully leveraging the power of annotation processing we will be able to skip a lot of repetition and save a lot of time.

You can play around with the code examples from this article on GitHub .

Arshad Syed

As a software developer I am always interested in learning new technologies. I am currently working on improving my full stack skills, and also on teaching technology.

Recent Posts

Getting started with spring security and spring boot.

Spring Security is a framework that helps secure enterprise applications. By integrating with Spring MVC, Spring Webflux or Spring Boot, we can create a powerful and highly customizable authentication and access-control framework.

Demystifying Transactions and Exceptions with Spring

One of the most convincing justifications for using the Spring Framework is its extensive transaction support. For transaction management, the Spring Framework offers a stable abstraction.

JUnit 5 Parameterized Tests

If you’re reading this article, it means you’re already well-versed with JUnit. Let me give you a summary of JUnit - In software development, we developers write code which does something simple as designing a person’s profile or as complex as making a payment (in a banking system).

best java annotations

Learn Java interactively.

Learn Java practically and Get Certified .

Popular Tutorials

Popular examples, reference materials.

Learn Java Interactively

Java Introduction

Java Flow Control

Java OOP (I)

Java OOP (II)

Java Inheritance

Java Method Overriding

Java OOP (III)

Java Annotations

Java Annotation Types

Java Reader/Writer

Additional Topics

Related Topics

In this tutorial, we will learn what annotations are, different Java annotations and how to use them with the help of examples.

Java annotations are metadata (data about data) for our program source code.

They provide additional information about the program to the compiler but are not part of the program itself. These annotations do not affect the execution of the compiled program.

Annotations start with @ . Its syntax is:

Let's take an example of @Override annotation.

The @Override annotation specifies that the method that has been marked with this annotation overrides the method of the superclass with the same method name, return type, and parameter list.

It is not mandatory to use @Override when overriding a method. However, if we use it, the compiler gives an error if something is wrong (such as wrong parameter type) while overriding the method.

Example 1: @Override Annotation Example

In this example, the method displayInfo() is present in both the superclass Animal and subclass Dog . When this method is called, the method of the subclass is called instead of the method in the superclass.

Annotations may also include elements (members/attributes/parameters).

1. Marker Annotations

Marker annotations do not contain members/elements. It is only used for marking a declaration.

Its syntax is:

Since these annotations do not contain elements, parentheses can be excluded. For example,

2. Single element Annotations

A single element annotation contains only one element.

If there is only one element, it is a convention to name that element as value .

In this case, the element name can be excluded as well. The element name will be value by default.

3. Multiple element Annotations

These annotations contain multiple elements separated by commas.

Any declaration can be marked with annotation by placing it above that declaration. As of Java 8, annotations can also be placed before a type.

1. Above declarations

As mentioned above, Java annotations can be placed above class, method, interface, field, and other program element declarations.

Example 2: @SuppressWarnings Annotation Example

If the above program is compiled without using the @SuppressWarnings("unchecked") annotation, the compiler will still compile the program but it will give warnings like:

We are getting the warning

because of the following statement.

This is because we haven't defined the generic type of the array list. We can fix this warning by specifying generics inside angle brackets <> .

2. Type annotations

Before Java 8, annotations could be applied to declarations only. Now, type annotations can be used as well. This means that we can place annotations wherever we use a type.

Constructor invocations

Type definitions

This declaration specifies non-null variable str of type String to avoid NullPointerException .

This declaration specifies a non-null list of type String .

This declaration specifies a list of non-null values of type String .

extends and implements clause

throws clause

Type annotations enable Java code to be analyzed better and provide even stronger type checks.

Types of Annotations

1. Predefined annotations

2. Meta-annotations

3. Custom annotations

These annotation types are described in detail in the Java Annotation Types tutorial.

Table of Contents

Sorry about that.

Related Tutorials

Java Tutorial

Try PRO for FREE

Related Articles

Annotations in Java

Annotations are used to provide supplemental information about a program. 

Hierarchy of Annotations in Java  


Note: This program throws compiler error because we have mentioned override, but not overridden, we have overloaded display.


If we remove parameter (int x) or we remove @override, the program compiles fine. 

Categories of Annotations

There are broadly 5 categories of annotations as listed:

Let us discuss and we will be appending code wherever required if so. 

Category 1: Marker Annotations

The only purpose is to mark a declaration. These annotations contain no members and do not consist of any data. Thus, its presence as an annotation is sufficient. Since the marker interface contains no members, simply determining whether it is present or absent is sufficient. @Override is an example of Marker Annotation. 

Category 2: Single value Annotations 

These annotations contain only one member and allow a shorthand form of specifying the value of the member. We only need to specify the value for that member when the annotation is applied and don’t need to specify the name of the member. However, in order to use this shorthand, the name of the member must be a value. 

Category 3: Full Annotations 

These annotations consist of multiple data members, names, values, pairs. 

Category 4: Type Annotations 

These annotations can be applied to any place where a type is being used. For example, we can annotate the return type of a method. These are declared annotated with @Target annotation .

Category 5: Repeating Annotations 

These are the annotations that can be applied to a single item more than once. For an annotation to be repeatable it must be annotated with the @Repeatable annotation, which is defined in the java.lang.annotation package. Its value field specifies the container type for the repeatable annotation. The container is specified as an annotation whose value field is an array of the repeatable annotation type. Hence, to create a repeatable annotation, firstly the container annotation is created, and then the annotation type is specified as an argument to the @Repeatable annotation.

  Predefined/ Standard Annotations

Java popularly defines seven built-in annotations as we have seen up in the hierarchy diagram.

Annotation 1: @Deprecated 

Annotation 2: @Override

It is a marker annotation that can be used only on methods. A method annotated with @Override must override a method from a superclass. If it doesn’t, a compile-time error will result (see this for example). It is used to ensure that a superclass method is actually overridden, and not simply overloaded.

Annotation 3: @SuppressWarnings 

It is used to inform the compiler to suppress specified compiler warnings. The warnings to suppress are specified by name, in string form. This type of annotation can be applied to any type of declaration.

Java groups warnings under two categories. They are deprecated and unchecked . Any unchecked warning is generated when a legacy code interfaces with a code that uses generics.

Annotation 4: @Documented 

It is a marker interface that tells a tool that an annotation is to be documented. Annotations are not included in ‘Javadoc’ comments. The use of @Documented annotation in the code enables tools like Javadoc to process it and include the annotation type information in the generated document.

Annotation 5: @Target 

It is designed to be used only as an annotation to another annotation. @Target takes one argument, which must be constant from the ElementType enumeration. This argument specifies the type of declarations to which the annotation can be applied. The constants are shown below along with the type of the declaration to which they correspond.

We can specify one or more of these values in a @Target annotation. To specify multiple values, we must specify them within a braces-delimited list. For example, to specify that an annotation applies only to fields and local variables, you can use this @Target annotation: @Target({ElementType.FIELD, ElementType.LOCAL_VARIABLE}) @Retention Annotation It determines where and how long the annotation is retent. The 3 values that the @Retention annotation can have:

Annotation 6: @Inherited 

@Inherited is a marker annotation that can be used only on annotation declaration. It affects only annotations that will be used on class declarations. @Inherited causes the annotation for a superclass to be inherited by a subclass. Therefore, when a request for a specific annotation is made to the subclass, if that annotation is not present in the subclass, then its superclass is checked. If that annotation is present in the superclass, and if it is annotated with @Inherited, then that annotation will be returned. 

Annotation 7: User-defined (Custom) 

User-defined annotations can be used to annotate program elements, i.e. variables, constructors, methods, etc. These annotations can be applied just before the declaration of an element (constructor, method, classes, etc). 

Syntax: Declaration

Do keep these certain points as rules for custom annotations before implementing user-defined annotations. 

This article is contributed by Rahul Agrawal. If you like GeeksforGeeks and would like to contribute, you can also write an article and mail your article to [email protected] See your article appearing on the GeeksforGeeks main page and help other Geeks.  Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above.

Please Login to comment...

Improve your Coding Skills with Practice

Start your coding journey now.



Utkarsh Jain

Feb 14, 2021

Java Annotations 101

Learn about the primary Java annotations and how to use them

🍎 If you have ever seen a Java codebase, there is a high chance you saw something like @Override or similar tags before a method or class. These tags are called Annotations . Annotations are metadata tags that help define additional information to classes, interfaces, methods, or fields. Annotations don’t add extra implementation to the functional code but help with extra information like:

☕️ Java has a comprehensive list of predefined annotations to use and even lets you define your own. Here is a list of the most widely used and essential annotations.

Predefined Annotations

🏎 The @Override annotation informs the compiler that the subclass element is overriding the parent class or superclass element. While it is not required to use this annotation when overriding a method , it helps prevent errors. If a method marked with override fails to override a superclass method correctly, the compiler generates an error.


⚠️ Compiler warnings are helpful if you read them, but they often create noise in the terminal. @SuppressWarnings will suppress those warnings. The Java compiler can throw numerous warnings but with @SuppressWarnings, you can conceal all warnings or select the warnings you want to suppress.

@SuppressWarnings({“unchecked”, “deprecated”}) will suppress unchecked and deprecated warnings.


☠️ The @deprecated annotation is also very common. It signifies that the annotated method has been deprecated and is not supported by the developers anymore. The compiler will not treat the deprecated method any differently from a regular method. So even though the method is callable, it may not return the ideal response. It is the documentation for developers.

📝 The @author tag, a simple annotation, documents the author of the method or file. It typically gets paired with some more info like the version, release number, etc.

⭕️ Oracle recommends you should write tags in the order:

Test Annotations

🧑🏽‍🏫️ Writing tests is a crucial aspect of the development cycle and is as (if not more) important as writing the base code itself. There are various annotations built explicitly for tests.

🖋 @Test tells JUnit that the annotated method should be executed as a test. To run the method, JUnit constructs a new instance of the class and then invokes the test method.

You can attest two optional parameters to the annotation:

🕒 @Timeout causes a test method to fail if the execution takes longer than the designated time measured on the clock in milliseconds.

For Example, the following fails(after 0.1 seconds):

📣 @Expected declares that the test method must throw a specific exception , or else the test fails.

For Example, the following fails:

🤷🏽‍♀️ The @Ignore test annotation ignores a test or a group of tests to avoid a potential execution failure.

You can @Ignore tests in two possible scenarios:

⏪ Methods annotated with @Before execute before each test. It is useful when you want to execute some code before running a test, like setting up the test environment. @Before was renamed to @BeforeEach , which also works.

⏮ The sibling annotation @BeforeAll or @BeforeClass is used when an expensive operation needs to be performed before a series of tests, like starting a server or making a database change.

⏩ @After is the opposite of the previous tag. All the methods annotated @After will be run after the test.

⏭ @AfterAll or @AfterClass methods are executed after all the tests of the class have been run.

All the @beforeAll and @afterall annotated methods have to be static, so they are executed before running the class’s tests. However, @before and @after methods should not be static , else the compiler will throw an error.

The above code will execute in the order:

🟢 0️⃣ startServer() 1️⃣ createTestLogFile() 2️⃣ test1() 3️⃣ deleteTestLogFile() 4️⃣ createTestLogFile() 5️⃣ test2() 6️⃣ deleteTestLogFile() 7️⃣ stopServer() 🔴

🍏 This list nowhere near being comprehensive, but it covers the most basic ones. Use the above examples to get a headstart on coding in Java with the best practices.

More from Javarevisited

A humble place to learn Java and Programming better.

About Help Terms Privacy

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store

Utkarsh Jain


Text to speech

Java Annotations

Java Annotations Video Tutorial

Java annotation purposes, accessing java annotations via java reflection, annotation elements, annotation placement, @deprecated, @suppresswarnings, create your own java annotations video tutorial, custom java annotation example, @documented.

Java annotations are used to provide meta data for your Java code. Being meta data, Java annotations do not directly affect the execution of your code, although some types of annotations can actually be used for that purpose.

Java annotations were added to Java from Java 5. This text covers Java annotations as they look in Java 8, Java 9 and beyond. As far as I know, Java annotations have not changed in later Java version, so this text should be valid for Java 8, 9, 10 and 11 programmers too.

I have created a set of videos that explain how Java Annotations work, and how to create your own Java Annotations. Here is a link to the YouTube playlist: Java Annotations - Playlist

Here is the first video in the Java annotations video tutorial playlist:

Java annotations are typically used for the following purposes:

Java has 3 built-in annotations that you can use to give instructions to the Java compiler. These annotations are explained in more detail later in this text.

Java annotations can be be used at build-time, when you build your software project. The build process includes generating source code, compiling the source, generating XML files (e.g. deployment descriptors), packaging the compiled code and files into a JAR file etc. Building the software is typically done by an automatic build tool like Apache Ant or Apache Maven. Build tools may scan your Java code for specific annotations and generate source code or other files based on these annotations.

Normally, Java annotations are not present in your Java code after compilation. It is possible, however, to define your own annotations that are available at runtime. These annotations can then be accessed via Java Reflection , and used to give instructions to your program, or some third party API. I have covered how to access Java annotations via reflection in my Java Reflection and Annotations tutorial.

Annotation Basics

A Java annotation in its shortest form looks like this:

The @ character signals to the compiler that this is an annotation. The name following the @ character is the name of the annotation. In the example above the annotation name is Entity .

A Java annotation can have elements for which you can set values. An element is like an attribute or parameter. Here is an example of a Java annotation with an element:

The annotation in this example contains a single element named tableName , with the value set to vehicles . Elements are enclosed inside the parentheses after the annotation name. Annotations without elements do not need the parentheses.

An annotation can contain multiple elements. Here is a multiple element Java annotation example:

In case an annotation contains just a single element, it is convention to name that element value , like this:

When an annotation just contains a single element named value , you can leave out the element name, and just provide the value. Here is an example of an annotation element with only the value provided:

You can place Java annotations above classes, interfaces, methods, method parameters, fields and local variables. Here is an example annotation added above a class definition:

The annotation starts with the @ character, followed by the name of the annotation. In this case, the annotation name is Entity . The Entity annotation is an annotation I have made up. It doesn't have any meaning in Java.

Here is a bigger example with annotations above both the class, fields, methods, parameters and local variables:

The annotations are again just annotations I have made up. They have no specific meaning in Java.

Built-in Java Annotations

Java comes with three built-in annotations which are used to give the Java compiler instructions. These annotations are:

Each of these annotations are explained in the following sections.

The @Deprecated annotation is used to mark a class, method or field as deprecated, meaning it should no longer be used. If your code uses deprecated classes, methods or fields, the compiler will give you a warning. Here is @Deprecated Java annotation example:

The use of the @Deprecated Java annotation above the class declaration marks the class as deprecated.

You can also use the @Deprecated annotation above method and field declarations, to mark the method or field as deprecated.

When you use the @Deprecated annotation, it is a good idea to also use the corresponding @deprecated JavaDoc symbol, and explain why the class, method or field is deprecated, and what the programmer should use instead. For instance:

The @Override Java annotation is used above methods that override methods in a superclass. If the method does not match a method in the superclass, the compiler will give you an error.

The @Override annotation is not necessary in order to override a method in a superclass. It is a good idea to use it still, though. In case someone changed the name of the overridden method in the superclass, your subclass method would no longer override it. Without the @Override annotation you would not find out. With the @Override annotation the compiler would tell you that the method in the subclass is not overriding any method in the superclass.

Here is an @Override Java annotation example:

In case the method doTheThing() in MySuperClass changes signature so that the same method in the subclass no longer overrides it, the compiler will generate an error.

The @SuppressWarnings annotation makes the compiler suppress warnings for a given method. For instance, if a method calls a deprecated method, or makes an insecure type cast, the compiler may generate a warning. You can suppress these warnings by annotating the method containing the code with the @SuppressWarnings annotation.

Here is a @SuppressWarnings Java annotation example:

The @Contended annotation, @jdk.internal.vm.annotation.Contended , is used to help avoid False Sharing , a concurrency performance degradation problem. You can read more about false sharing in Java via the above link, and also about how the @Contended annotation works.

Creating Your Own Java Annotations

It is possible to create your own (custom) Java annotations. Annotations are defined in their own file, just like a Java class or interface. I have created a video tutorial about creating your own Java Annotations, by the way. You can find it just below this paragraph. If you prefer a textual explanation, just scroll down over the video and continue reading.

Here is custom Java annotation example:

This example defines an annotation called MyAnnotation which has four elements. Notice the @interface keyword. This signals to the Java compiler that this is a Java annotation definition.

Notice that each element is defined similarly to a method definition in an interface. It has a data type and a name. You can use all primitive data types as element data types. You can also use arrays as data type. You cannot use complex objects as data type.

To use the above annotation, you could use code like this:

As you can see, I have to specify values for all elements of the MyAnnotation annotation.

Element Default Values

You can specify default values for an element. That way the element becomes optional and can be left out. Here is an example of how the annotation definition looks with a default value for an element:

The value element can now be left out when using the annotation. If you leave it out, it will be considered as if you had used the default value for the value element. Here is an example of an annotation with an element value left out, so that element is set to the default value:

Notice that the value element is no longer present.

You can specify for your custom annotation if it should be available at runtime, for inspection via reflection. You do so by annotating your annotation definition with the @Retention annotation. Here is how that is done:

Notice the @Retention annotation added above the MyAnnotation definition:

This is what signals to the Java compiler and JVM that the annotation should be available via reflection at runtime. Accessing annotations at runtime is covered in my Java Reflection and Annotations tutorial , which is part of my Java Reflection Tutorial .

The RetentionPolicy class contains two more values you can use:

RetentionPolicy.CLASS means that the annotation is stored in the .class file, but not available at runtime. This is the default retention policy, if you do not specify any retention policy at all.

RetentionPolicy.SOURCE means that the annotation is only available in the source code, and not in the .class files and not a runtime. If you create your own annotations for use with build tools that scan the code, you can use this retention policy. That way the .class files are not polluted unnecessarily.

You can specify which Java elements your custom annotation can be used to annotate. You do so by annotating your annotation definition with the @Target annotation. Here is a @Target Java annotation example:

This example shows a Java annotation that can only be used to annotate methods.

The ElementType class contains the following possible targets:

Most of these are self explaining, but a few are not. Therefore I will explain the targets which are not obvious.

The ANNOTATION_TYPE target means Java annotation definitions. Thus, the annotation can only be used to annotate other annotations. Like the @Target and @Retention annotations.

The TYPE target means any type. A type is either a class, interface, enum or annotation.

The @Inherited annotation signals that a custom Java annotation used in a class should be inherited by subclasses inheriting from that class. Here is an @Inherited Java annotation example:

In this example the class MySubClass inherits the annotation @MyAnnotation because MySubClass inherits from MySuperClass , and MySuperClass has a @MyAnnotation annotation.

The @Documented annotation is used to signal to the JavaDoc tool that your custom annotation should be visible in the JavaDoc for classes using your custom annotation. Here is a @Documented Java annotation example:

When generating JavaDoc for the MySuperClass class, the @MyAnnotation is now included in the JavaDoc.

You will not use the @Documented annotation often, but now you know it exists, if you should need it.

best java annotations


  1. Java Annotations

    best java annotations

  2. Annotations in Java

    best java annotations

  3. Annotations in Java

    best java annotations

  4. Annotations in Java

    best java annotations

  5. Java Annotations Tutorial

    best java annotations

  6. Java annotations

    best java annotations


  1. Don't Be a _____ About It

  2. Lady Justice


  4. Intro to Java

  5. 16 Java Intro Summary

  6. Java Annotations


  1. Overview of Java Built-in Annotations

    2. What an Annotation Is ... Simply put, annotations are Java types that are preceded by an “@” symbol. Java has had annotations ever since the

  2. 10 Spring Framework Annotations Java Developer should learn

    10+ Essential Spring Core Annotations for Java developers · 1. @Configuration · 2. @ComponentScan · 3. @Bean · 4. @Component · 5. @Service · 6. @Autowired · 7. @Lazy.

  3. 5 Annotations Every Java Developer Should Know

    Annotations have been an indispensable part of Java since their introduction in JDK 5. While some are more popular than others, there are 5

  4. Top 10 most frequently used Annotation example

    Top 10 most frequently used Annotation example · 1. @Deprecated Annotation example · 2. @SuppressWarnings Annotation example · 3. @Override Annotation example · 4.

  5. An Introduction to Annotations and Annotation Processing in Java

    An annotation is preceded by the @ symbol. Some common examples of annotations are @Override and @SuppressWarnings . These are built-in

  6. Annotations: An Inside Look

    How annotations work, how best to use them, and how to write your own ... Annotations appeared on the Java platform for Java 5 more than ten years

  7. Java Annotations (With Examples)

    Use of Annotations · Compiler instructions - Annotations can be used for giving instructions to the compiler, detect errors or suppress warnings. · Compile-time

  8. Annotations in Java

    Annotations in Java · Annotations start with '@'. · Annotations do not change the action of a compiled program. · Annotations help to associate

  9. Basic Java Annotations

    Learn about the basic Java Annotations and how to use them. ... above examples to get a headstart on coding in Java with the best practices.

  10. Java Annotations

    A Java annotation is a small comment-like construct you can insert before class, method and field declarations. Annotations can be used to