How to make a #Documented annotation retaining generics information? - java

I currently have this annotation defined:
#Documented
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.SOURCE)
#Beta
public #interface Needs
{
Class<?>[] value();
}
The problem is that while I can do:
#Needs({SomeClass.class, OtherClass.class})
I cannot do, for instance:
#Needs(Map<String, SomeClass>)
The purpose is to have it documented and retain generics information like the above. Is it possible?

The Java Language Specification writes:
It is a compile-time error if the return type of a method declared in an annotation type is not one of the following: a primitive type, String, Class, any parameterized invocation of Class, an enum type (§8.9), an annotation type, or an array type (§10) whose element type is one of the preceding types.
The reason for this restriction is that annotation values are evaluated at compile time, and only the values are stored. Therefore, these values can not be arbitrary objects, because it would be unclear how to store them in the class file, and unmarshall them at runtime.
The usual solution is the nested annotation trick:
public #interface Needs {
Need[] value();
}
public #interface Need {
String key();
Class value();
}
which you can then use like
#Needs([
#Need(key = "aKey", value = A.class)
#Need(key = "anotherKey", value = Another.class)
])

Related

How to get annotation used on inner generic type?

My question is somewhat a little more advanced reflection problem.
Suppose you have a class:
import java.util.List;
public class Sample
{
private List<#First List<#Second String>> field;
}
As you see, type of field is List<List<String>>. Assume you have 2 different annotations: #First and #Second. These annotations are put on this field's generic type, respectively. Now, my goal is to access these both annotations at runtime.
Here is my code:
Field field = Sample.class.getDeclaredField("field");
AnnotatedType annotatedType = field.getAnnotatedType();
AnnotatedParameterizedType annotatedParameterizedType = (AnnotatedParameterizedType) annotatedType;
When I invoke getAnnotatedType() on field, it returns me an AnnotatedParameterizedType.
AnnotatedType annotatedActualTypeArgument = annotatedParameterizedType.getAnnotatedActualTypeArguments()[0];
Annotation firstAnnotation = annotatedActualTypeArgument.getAnnotations()[0];
getAnnotatedActualTypeArguments() method actually gives me the #First annnotation.
ParameterizedType innerType = (ParameterizedType) annotatedActualTypeArgument.getType();
However, when I try to get type of the inner generic argument, it gives me a ParameterizedType. Which correctly defines the type of inner-most argument: List<String>. But, because it is not of type AnnotatedParameterizedType, I cannot access #Second annotation.
Is there any way I can access the second annotation as well at runtime?
First of all the annotation type Second has to be declared with #Retention set to RetentionPolicy.RUNTIME, so that they are retained in the class files and can be read using reflection by the JVM.
You should be able to access the second annotation the same way you did with the first one. Convert annotatedActualTypeArgument to AnnotatedParameterizedType, then get the annotated actual type argument:
AnnotatedParameterizedType innerAnnotatedParameterizedType = (AnnotatedParameterizedType) annotatedActualTypeArgument;
AnnotatedType innerAnnotatedActualTypeArgument = innerAnnotatedParameterizedType.getAnnotatedActualTypeArguments()[0];
Annotation secondAnnotation = innerAnnotatedActualTypeArgument.getAnnotations()[0];

default {} in #interface in Spring

Just read some source code from Spring-web-4.2.4, found that the ControllerAdvice (annotation) is pretty interesting:
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
#Documented
#Component
public #interface ControllerAdvice {
#AliasFor("basePackages")
String[] value() default {};
#AliasFor("value")
String[] basePackages() default {};
//......
}
I do not consider default {} as the new feature of Java 8?
In Java #interface is a some kind of reserved word (keyword) for defining annotations. So you can be sure that the class you listed above is an annotation definition. In this classes default keyword could be used to define default value for annotation properties. This feature was introduced at the same time as annotations were introduced in the language.
The default keyword is used in annotations to set a default value for a corresponding annotation type (it, in turn, allows you not to specify a value of this type every time you write the annotation);
{} is just an array literal which means an empty array.

How can I define my Custom Annotation to use a subset of target elements?

Question:
Is it possible to target multiple element types? (More than one, less than all)
Details:
I'm trying create an annotation that is only acceptable on Methods and Fields.
I know if I don't specify the #Target annotation I can use my custom annotation on all elements. However, I want compile time safety on element types that conflict with my logic.
In C#/.NET
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Method)]
public class MyAttribute : Attribute
{
...
Java Attempts
Multiple Target Annotations:
#Target(ElementType.METHOD)
#Target(ElementType.FIELD)
public #interface MyAnnotation
{
Compiler Error:
MyAnnotation.java:8: error: duplicate annotation
OR'd Values:
#Target(ElementType.METHOD | ElementType.FIELD)
public #interface MyAnnotation
{
Compiler Error:
MyAnnotation.java:7: error: bad operand types for binary operator '|'
Annotation Array
#Targets({#Target(ElementType.METHOD),#Target(ElementType.FIELD)})
public #interface MyAnnotation
{
Compiler Error:
MyAnnotation.java:7: error: cannot find symbol
#Targets({#Target(ElementType.METHOD),#Target(ElementType.FIELD)})
^symbol: class Targets
Java - The input is an array of ElementTypes. To define array values within an annotation, we comma separate the values within curly braces:
#Target({ElementType.METHOD, ElementType.FIELD})
public #interface MyAnnotation {
}

Provide similar to 'NO_VALUE' default for Annotation type attibute in the Annotation

I have two annotations. The first is used from the second:
#Target({ })
#Retention(RUNTIME)
public #interface A {
String value() default "";
}
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface B {
A a() default ???;
}
The logic that #B can be used without any attributes, but, of course, it doesn't mean (by Annotation specification) that it will have nulls for its attributes.
From other side #A.value() == "" is also OK for my logic. That means:
A a() default #A;
Isn't for me.
So, I need a case, when I can determine that #B.a() is something like 'NO_VALUE' and it should be protected from end-user.
static final A NO_A = new A() {};
A a() default NO_A;
Doesn't help: it isn't compiled.
As a workaround I use an array:
A[] a() default {};
And check in the annotation processor the size of a attribute.
Are there some other options to mark a() with something default to make it 'NULL'-like and get rid of an array style ?
There doesn't seem to be any clean way to create default null values for annotation fields. Here's some information why it was design this way and workarounds when using class types: Error setting a default null value for an annotation's field
I think using arrays like you proposed is a good way of handling this. Just document that it's an array for technical reasons and throw an error when used with more than one element.
The only other solution that comes to my mind is using magic strings as the value of the default A. Depending on the use case I would either choose some long random string that is unlikely to be used any users or document whatever other special value is used.
public #interface B {
final String DEFAULT = "_a_default_value";
A a() default #A(DEFAULT);
}

How #Target(ElementType.ANNOTATION_TYPE) works

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.
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.
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.
Annotation is defined like a ordinary Java interface, but with an '#' preceding the interface keyword (i.e., #interface ). Annotations are used to provide supplemental information about a program. On the other hand, an interface can be defined as a container that stores the signatures of the methods to be implemented in the code segment.
WHY to use #Target(ANNOTATION_TYPE) value?
When there is need to apply an annotation to an 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();
}
What are the annotated annotations good for?
They are good or more precisely necessary if they are used to annotate other annotations.
What is their contribution?
They make possible to apply an annotation directly to an another annotation, that is a different thing than applying an annotation to a standard Java class or to method and so on.
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 may want that the program checks data validity. In that case, there might be need to create a new annotation and apply another annotations to this annotation. It is simple to add some data validity checks to this model by adding annotations to the class. For example, to check that some value is not null (#notNull) or email is valid (#ValidEmail) or length of a field is more than x characters (#Size). However, it is possible that there is not built in Java annotations for all purposes. For example, it is so if you liked to check if password and its matchingPassword are same. 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).
In other words, the annotation class Constraint, like the other annotations in this class also, must have ANNOTATION_TYPE as a value of target annotation.
Now the password equality check is easy to include to data model class simply by adding annotation #PasswordMatches:
#PasswordMatches
public class UserDto {
...
}
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());
}
}
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 applied frequently to custom annotations are #Retention, #Documented and #Target itself.
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.
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...
}

Categories