How @Target(ElementType.ANNOTATION_TYPE) works
JavaAnnotationsJava Problem Overview
Java annotations are marked with a @Target
annotation to declare possible joinpoints which can be decorated by that annotation. Values TYPE
, FIELD
, METHOD
, etc. of the ElementType
enum are clear and simply understandable.
Question
WHY to use @Target(ANNOTATION_TYPE)
value? What are the annotated annotations good for? What is their contribution? Give me an explanation of an idea how it works and why I should use it. Some already existing and well-known example of its usage would be great too.
Java Solutions
Solution 1 - Java
You can use an annotated annotation to create a meta-annotation, for example consider this usage of @Transactional
in Spring:
/**
* Shortcut and more descriptive "alias" for {@code @Transactional(propagation = Propagation.MANDATORY)}.
*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Transactional(propagation = Propagation.MANDATORY)
public @interface RequiresExistingTransaction {
}
When you enable Spring to process the @Transactional
annotation, it will look for classes and methods that carry @Transactional
or any meta-annotation of it (an annotation that is annotated with @Transactional
).
Anyway this was just one concrete example how one can make use of an annotated annotation. I guess it's mostly frameworks like Spring where it makes sense to use them.
Solution 2 - Java
Each annotation annotated by @Target(ElementType.ANNOTATION_TYPE)
is called Meta-annotation
. That means, you can define your own custom annotations that are an amalgamation of many annotations combined into one annotation to create composed annotations
.
A good example from Android world is StringDef
>Denotes that the annotated String element, represents a logical type and that its value should be one of the explicitly named constants. > > @Retention(SOURCE) > @StringDef({POWER_SERVICE, WINDOW_SERVICE, LAYOUT_INFLATER_SERVICE}) > public @interface ServicesName {} > > public static final String POWER_SERVICE = "power"; > public static final String WINDOW_SERVICE = "window"; > public static final String LAYOUT_INFLATER_SERVICE = "layout_inflater";
Code inspector will treat @ServicesName
and @WeekDays
in the same way as @StringDef
.
As a result we can create as much named StringDef
's as we need and override set of constants. @Target(ElementType.ANNOTATION_TYPE)
it is a tool that allows to extend the use of annotations.
Solution 3 - Java
For example, if annotation looks like
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface SomeAnnotation {
String description() default "This is example for class annotation";
}
the compiler will complain in this situation
@SomeAnnotation
public class SomeClass {
@SomeAnnotation // here it's complaning
public void someMethod(){}
}
If you change
@Target(ElementType.TYPE)
to
@Target({ElementType.METHOD, ElementType.TYPE})
it won't complain anymore.
Solution 4 - Java
- WHY to use @Target(ANNOTATION_TYPE) value?
Simply put: when there is need to apply annotation to another annotation. If you look at the source codes of the common Java annotations, you see often this code pattern:
@Target(ANNOTATION_TYPE)
public @interface TheAnnotation
{
...
}
for example,
@Documented
@Target({ ANNOTATION_TYPE })
@Retention(RUNTIME)
public @interface Constraint {
public Class<? extends ConstraintValidator<?, ?>>[] validatedBy();
}
2. What are the annotated annotations good for?
They are good or more precisely necessary if that annotation is used in another annotation (definition) classes.
- What is their contribution?
They make possible to apply annotation directly to another annotation, that is different thing than applying annotation to standard Java class or to class method etc.
- Give me an explanation of an idea how it works and why I should use it.
For example, if you create a data model class and you want it to check data validity, there might be need to have such value in @Target annotation in some annotation definition classes. It is easy to include these data validity checks by adding annotations to the class: some value is not null (@notNull), email is valid (@ValidEmail), length of the field is more than x characters (@Size) etc. There are many ready annotations to make data validity checks but not necessarily for all purposes, for example if you would like to check if password and its matchingPassword are same simply by adding annotation @PasswordMatches. This is possible by creating the annotation class PasswordMatches:
@Target({TYPE})
@Retention(RUNTIME)
@Constraint(validatedBy = PasswordMatchesValidator.class)
@Documented
public @interface PasswordMatches {
String message() default "Passwords don't match";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
Note there is line
@Constraint(validatedBy = PasswordMatchesValidator.class)
i.e. an annotation is included to this annotation definition class.
The PasswordMatchesValidator class could look like this:
public class PasswordMatchesValidator implements ConstraintValidator<PasswordMatches, Object> {
@Override
public void initialize(final PasswordMatches constraintAnnotation) {}
@Override
public boolean isValid(final Object obj, final ConstraintValidatorContext context) {
final UserDto user = (UserDto) obj;
return user.getPassword().equals(user.getMatchingPassword());
}
}
Now the password equality check is easy to include to data model class simply by adding annotation @PasswordMatches:
@PasswordMatches
public class UserDto {
...
}
Note here the Password check is not possible only by adding annotation @PasswordMatches to the class and the PasswordMatches annotation class needs to have line @Constraint(validatedBy = PasswordMatchesValidator.class). In other words, an annotation is used to annotate another annotation. This is possible because @Constraint annotation (definition) class has line @Target({ ANNOTATION_TYPE }).
Main reason why to annotate annotations is to make possible using annotations in annotation (definition) class. Especially, if you want to customize annotations with your annotation then you need to include ANNOTATION_TYPE to @Target annotation value array to your custom annotation class.
- Some already existing and well-known example of its usage would be great too.
There is quite well-known example in item 4, but another known annotations which are used to annotations (and whose implementations has to have @Target(ANNOTATION_TYPE) line) are @Retention, @Documented and @Target itself.
Solution 5 - Java
Annotation are basically additional metadata (information) that goes along with your code. It can be placed along side types (Classes, Interfaces), methods, and arguments.
It is often useful during compile time and runtime. Many popular APIs such as Java EE 5+, Spring, AspectJ leverage annotation for code clarity and consistency.
Using annotation often allows code to be more readable, more easily understood.
I'd recommend you read through the annotation chapter on Java tutorial
In the past metadata are often given as an xml file, and it's difficult for someone trying to understand the code if they have to lookup a different xml configuration file. The latest Java servlet API allows mapping of servlet simply by using annotation -- as opposed of web.xml mapping:
@WebServlet("/response")
public class ResponseServlet extends HttpServlet {
// servlet code here...
}