How do different retention policies affect my annotations?
JavaAnnotationsJava Problem Overview
Can anyone explain in a clear way the practical differences between the java.lang.annotation.RetentionPolicy
constants SOURCE
, CLASS
, and RUNTIME
?
I'm also not exactly sure what the phrase "retaining annotation" means.
Java Solutions
Solution 1 - Java
> - RetentionPolicy.SOURCE
: Discard during
> the compile. These annotations don't
> make any sense after the compile has
> completed, so they aren't written to
> the bytecode.
> Example: @Override
, @SuppressWarnings
>
>
> - RetentionPolicy.CLASS
: Discard during
> class load. Useful when doing
> bytecode-level post-processing.
> Somewhat surprisingly, this is the
> default.
>
> - RetentionPolicy.RUNTIME
: Do not
> discard. The annotation should be
> available for reflection at runtime.
> Example: @Deprecated
Source:
The old URL is dead now
hunter_meta and replaced with hunter-meta-2-098036. In case even this goes down, I am uploading the image of the page.
Image (Right Click and Select 'Open Image in New Tab/Window')
Solution 2 - Java
According to your comments about class decompilation, here is how I think it should work:
-
RetentionPolicy.SOURCE
: Won't appear in the decompiled class -
RetentionPolicy.CLASS
: Appear in the decompiled class, but can't be inspected at run-time with reflection withgetAnnotations()
-
RetentionPolicy.RUNTIME
: Appear in the decompiled class, and can be inspected at run-time with reflection withgetAnnotations()
Solution 3 - Java
Minimal runnable example
Language level:
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.SOURCE)
@interface RetentionSource {}
@Retention(RetentionPolicy.CLASS)
@interface RetentionClass {}
@Retention(RetentionPolicy.RUNTIME)
@interface RetentionRuntime {}
public static void main(String[] args) {
@RetentionSource
class B {}
assert B.class.getAnnotations().length == 0;
@RetentionClass
class C {}
assert C.class.getAnnotations().length == 0;
@RetentionRuntime
class D {}
assert D.class.getAnnotations().length == 1;
}
Bytecode level: using javap
we observe that the Retention.CLASS
annotated class gets a RuntimeInvisible class attribute:
#14 = Utf8 LRetentionClass;
[...]
RuntimeInvisibleAnnotations:
0: #14()
while Retention.RUNTIME
annotation gets a RuntimeVisible class attribute:
#14 = Utf8 LRetentionRuntime;
[...]
RuntimeVisibleAnnotations:
0: #14()
and the Runtime.SOURCE
annotated .class
does not get any annotation.
Examples on GitHub for you to play with.
Solution 4 - Java
Retention Policy: A retention policy determines at what point an annotation is discarded. It is s specified using Java's built-in annotations: @Retention
[About]
1.SOURCE: annotation retained only in the source file and is discarded
during compilation.
2.CLASS: annotation stored in the .class file during compilation,
not available in the run time.
3.RUNTIME: annotation stored in the .class file and available in the run time.
Solution 5 - Java
- CLASS :Annotations are to be recorded in the class file by the compiler but need not be retained by the VM at run time.
- RUNTIME :Annotations are to be recorded in the class file by the compiler and retained by the VM at run time, so they may be read reflectively.
- SOURCE :Annotations are to be discarded by the compiler.