In the source code of @Retention annotation in java, @Retention is used in its definition itself, hows that possible.
Even the RetentionPolicy is set at RUNTIME, so how could it get executed before its not ready to run.
package java.lang.annotation;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
/**
* Returns the retention policy.
* @return the retention policy
*/
RetentionPolicy value();
}
This is not really recursive. It is nothing but a forward reference to a class respectively interface which is following "later" on. And Java allows using forward references in general. There are various restrictions to that (see the Java Language Specification, for example section 8.3.2.2) - but none of these restrictions would apply here.
Beyond that: keep in mind there is no special compilation step here. The compiler simply creates a ordinary class file for the Retention interface. But then: the compiler most likely has hardcoded knowledge about this interface. In case RetentionPolicy.SOURCE is used, the compiler will exclude the annotation even from the compiled class file. This means that the compiler must be doing some sort of checking (to figure if something is annotated and has SOURCE policy enabled).
In other words: the compiler might contain something like
if (x instaceof Retention) ...
and this code exists within the compiler. The above works fine when compiling some other annotation, but it also works when the Retention interface itself is compiled.
But the key message is: there is no recursion, just a forward reference. Something gets used that is defined later on.
It doesn't need a Retention
class. Source code first convert to AST. It just need the Retention
's qualifield name to get the annotation value. Here is code from OpenJDK
Define the Retention
by class name:
// com.sun.tools.javac.code.Symtab
protected Symtab(Context context) throws CompletionFailure {
...
retentionType = enterClass("java.lang.annotation.Retention");
...
}
Use the com.sun.tools.javac.code.Type retentionType
to get the RetentionPolicy
from AST (line 4 syms.retentionType.tsym
):
// com.sun.tools.javac.code.Types
public RetentionPolicy getRetention(Attribute.Compound a) {
RetentionPolicy vis = RetentionPolicy.CLASS; // the default
Attribute.Compound c = a.type.tsym.attribute(syms.retentionType.tsym);
if (c != null) {
Attribute value = c.member(names.value);
if (value != null && value instanceof Attribute.Enum) {
Name levelName = ((Attribute.Enum)value).value.name;
if (levelName == names.SOURCE) vis = RetentionPolicy.SOURCE;
else if (levelName == names.CLASS) vis = RetentionPolicy.CLASS;
else if (levelName == names.RUNTIME) vis = RetentionPolicy.RUNTIME;
else ;// /* fail soft */ throw new AssertionError(levelName);
}
}
return vis;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With