Is it possible to have both #Retention(Source) and #Inherited functioning on an annotation definition or does RetentionPolicy.Source cancels Inherited annotation?
In my tests, latter seems to be the outcome however I couldn't find any reference for this, which is what I'm looking for.
I was hoping retention policy at source level and inherited would work with help from processing environment.
#Retention and #Inherited serve different purposes.
The javadoc of #Retention states that it
Indicates how long annotations with the annotated type are to be retained.
The javadoc of #Inherited states that it
Indicates that an annotation type is automatically inherited.
An annotation type cannot be inherited if it doesn't exist.
If the annotation exists at SOURCE level, then #Inherited will also work at SOURCE level.
If the annotation exists at CLASS level, then #Inherited will also work at CLASS level.
If the annotation exists at RUNTIME level, then #Inherited will also work at RUNTIME level.
Related
I have a nice field annotation
#Target(ElementType.FIELD)
#Retention(RetentionPolicy.RUNTIME)
public #interface Foo {
// lots of useful, mandatory values here
}
and I would like to create a type annotation
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.CLASS)
public #interface Bar {
...
}
such that any types annotated #Bar will throw compiler warnings if they contain fields that are not annotated with #Foo.
In other words, I would like Bar to enforce a contract in which all of the #Bar-annotated class' fields must have a #Foo annotation, otherwise I will get a nice warning from my compiler.
Is this possible?
Thanks!
There is no annotation that makes javac do that directly.
However, there are things called 'annotation processors'. They run as part of a compilation run, and they can generate errors and warnings. You can write one, having it trigger on any source file containing type(s) annotated with #Bar, inspecting each field inside, and emitting errors if you find any without a #Foo annotation.
Annotation Processors can work on annotations with any retention level.
This question already has an answer here:
How is it possible that an annotation can be an annotation to itself?
(1 answer)
Closed 7 years ago.
I stumbled across into the source code for the "Documented" Java Annotation recently. It looks like this:
#Documented
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.ANNOTATION_TYPE)
public #interface Documented {
}
What the purpose of "#Documented" within Documented itself?
From the documentation:
Indicates that annotations with a type are to be documented by javadoc and similar tools by default. This type should be used to annotate the declarations of types whose annotations affect the use of annotated elements by their clients. If a type declaration is annotated with Documented, its annotations become part of the public API of the annotated elements.
#Documented is a meta annotation - it annotates another annotation type. When an annotation type is annotated by #Documented, tools like javadoc should include the annotation when it is used somewhere in the code.
For example, the #Deprecated annotation type is annotated with #Documented. It's pretty important to know if something is deprecated, so #Deprecated is considered part of the public API and should be included in the documentation.
On the other hand, #SuppressWarnings is just a hint for the compiler and not important for the API, so it is not annotated by #Documented.
The #Documented annotation type also annotates itself. Basically that just means that you will see any usage of #Documented in the documentation. This is done so that you can see if any annotation type will be documented or not.
Here's an example of it in the JavaDoc of AnnotationLiteral e.g.
"An instance of an annotation type may be obtained by subclassing AnnotationLiteral."
public abstract class PayByQualifier extends AnnotationLiteral<PayBy> implements PayBy {
}
PayBy paybyCheque = new PayByQualifier() {
public PaymentMethod value() {
return CHEQUE;
}
};
There is a more complete example in Section 5.6.3 in the CDI spec.
5.6.3. Using AnnotationLiteral and TypeLiteral
javax.enterprise.util.AnnotationLiteral makes it easier to specify qualifiers when calling select():
#Qualifier
#Retention(RUNTIME)
#Target({METHOD, FIELD, PARAMETER, TYPE})
public #interface Synchronous {}
#Qualifier
#Retention(RUNTIME)
#Target({METHOD, FIELD, PARAMETER, TYPE})
public #interface PayBy {
PaymentMethod value();
#Nonbinding String comment() default "";
}
public PaymentProcessor getSynchronousPaymentProcessor(PaymentMethod paymentMethod) {
class SynchronousQualifier extends AnnotationLiteral<Synchronous>
implements Synchronous {}
class PayByQualifier extends AnnotationLiteral<PayBy>
implements PayBy {
public PaymentMethod value() { return paymentMethod; }
}
return anyPaymentProcessor.select(new SynchronousQualifier(), new PayByQualifier()).get();
}
And finally according to section 9.6 of the Java annotation types spec.:
Unless explicitly modified herein, all of the rules that apply to normal interface declarations apply to annotation type declarations.
For example, annotation types share the same namespace as normal class and interface types; and annotation type declarations are legal wherever interface declarations are legal, and have the same scope and accessibility.
However, the Java compiler complains when I attempt to implement an annotation. In particular, Intellij warns:
"Reports any classes declared as implementing or extending an annotation interface. While it is legal to extend an annotation interfaces, IT IS NEARLY MEANINGLESS, AND DISCOURAGED." (emphasis mine).
Here is the error message as displayed from within Intellij:
The Intellij warning seems to contradict the official Java documentation. I presume the Intellij warning is based upon a warning that comes from the Java compiler. What is correct? The Intellij and/or compiler warning or the documentation?
Annotations types are used as meta data. The typical use case for annotations, at runtime, is with reflection. You annotate something, then you use reflection to retrieve the annotation, process it, and possibly enhance the target. The annotation instances are created and given to you by the JVM through calls to the reflection API.
In that regard, creating your own annotation type instances, which AnnotationLiteral makes easier to do, is kind of pointless since you have no target, since nothing was actually annotated.
It can be useful for cases where you need to mock an annotation type instance or you want to inject some functionality that only exists when processing annotations.
Intellij is simply warning you that it's uncommon.
From Intellij support:
"We can change warning text for example to: "While it is legal to extend an annotation interface it is often done by accident, and the result won't be usable as an annotation." Note that you can always suppress the warning for the statement."
My response:
The proposed solution... would require developers to always suppress the warning for the statement. This solution is poor because the code would be littered with #SuppressWarning or, worse, the developer would need to turn off the warning altogether. The best and most useful solution, would be to not display any warning whatsoever if the developer extends AnnotationLiteral or TypeLiteral and implements an #interface at the same time.
A YouTrack Issue was filed.
I was reading this question, where #SuppressWarnings annotation is used on class level.
Suppose I have multiple classes in my application, so is there a way that I can use #SuppressWarnings on application level? As applying #SuppressWarnings on every class is redundant for me.
this is what javadoc says for #SupressWarnings
#Target(value={TYPE,FIELD,METHOD,PARAMETER,CONSTRUCTOR,LOCAL_VARIABLE})
#Retention(value=SOURCE)
public #interface SuppressWarnings
#Target clearly mentions places where #SupressWarnings can be applied. So you can not apply at application level. Even doc go ahead and says
As a matter of style, programmers should always use this annotation on the most deeply nested element where it is effective. If you want to suppress a warning in a particular method, you should annotate that method rather than its class.
So its discouraged to do at parent level where it is not applicable.
I was browsing through the documentation of JDK 7 when I noticed an annotation called #Target in package java.lang.annotation. The header of that class is
#Documented
#Retention(value=RUNTIME)
#Target(value=ANNOTATION_TYPE)
public #interface Target
Now, #Target is used as an annotation to itself. How is this possible? #Target is used in the header even before it is declared. I tried this with annotations I had written, and it worked as well. Can anyone explain what's happening here?
The JLS specifically anticipates this, in section 9.6 Annotation Types:
If an annotation a
(ยง9.7)
on an annotation type declaration corresponds to an annotation type
T, and T has a (meta-)annotation m that corresponds to
java.lang.annotation.Target, then m must have either an element
whose value is java.lang.annotation.ElementType.ANNOTATION_TYPE, or
an element whose value is java.lang.annotation.ElementType.TYPE, or
a compile-time error occurs.
No other part of section 9.6 or 9.7 says anything about it being illegal for an annotation declaration to be annotated with a reference to the annotation being declared.