Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Recursive usage of @Retention annotation , how is it possible?

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();
}
like image 883
Bharat Pahalwani Avatar asked Nov 23 '17 13:11

Bharat Pahalwani


2 Answers

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.

like image 75
GhostCat Avatar answered Oct 17 '22 04:10

GhostCat


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;
}
like image 23
Dean Xu Avatar answered Oct 17 '22 02:10

Dean Xu