57

What is the practical difference between RetentionPolicy.CLASS and RetentionPolicy.RUNTIME?

It looks like both are recorded into the bytecode and both may be accessed at the run-time anyway.

skaffman
  • 398,947
  • 96
  • 818
  • 769
Dima
  • 1,326
  • 2
  • 13
  • 19
  • possible duplicate of [Java Annotations - looking for an example of RetentionPolicy.CLASS](http://stackoverflow.com/questions/3849593/java-annotations-looking-for-an-example-of-retentionpolicy-class) – skaffman May 11 '11 at 22:22
  • 1
    Also see http://stackoverflow.com/questions/3107970/annotations-retention-policy – skaffman May 11 '11 at 22:22
  • 2
    `CLASS` cannot be accessed at runtime using the Reflection API. – Adam Arold Oct 09 '14 at 10:06
  • CLASS annotations can be used by special libraries which operate directly with byte-code. For example, BCEL - Bytecode Engineering Library. – Vitaly May 28 '16 at 22:04
  • read more here - https://stackoverflow.com/a/59236293/4770877 – yoAlex5 Dec 30 '19 at 12:14

3 Answers3

73

both may be accessed at the run-time anyway.

That's not what the javadoc says:

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.

CLASS: Annotations are to be recorded in the class file by the compiler but need not be retained by the VM at run time.

In practice, I'm not aware of any use-cases for CLASS. It would only be useful if you wanted to read the bytecode programmatically, as opposed to via the classloader API, but that's a very specialised case, and I don't know why you wouldn't just use RUNTIME.

Ironically, CLASS is the default behaviour.

skaffman
  • 398,947
  • 96
  • 818
  • 769
  • I read that of course. Sounds like "need not" does not exclude "may" That is why the question. – Dima May 11 '11 at 22:17
  • @Dima: If the spec says an implementation doesn't have to do a thing, you'd be foolish to assume it *does* do that thing. Assume it doesn't. – skaffman May 11 '11 at 22:18
  • You must be right. What is not clear is the meaning of words "implementation doesn't have to do a thing" for this rather specific case. At least as it is about RetentionPolicy.CLASS case I assume the implementation MUST keep information in the bytecode. Will anything stop me from extracting it from the bytecode using reflection? If yes (will stop) then what is the meaning of "keeping information in the bytecode"? – Dima May 11 '11 at 22:23
  • 7
    @Dima: You can extract it from the bytecode if you read the bytecode directly. If you use the reflection API, it likely won't be there. – skaffman May 11 '11 at 22:24
  • That may be right. Not sure if existence of RetentionPolicy.CLASS makes much sense in this case. Maybe something more was behind it initially ... – Dima May 11 '11 at 23:05
  • Well, I actually see a use-case for CLASS retention: using AOP tools, with load-time weaving for example with a Java Agent, you may want to do things when loading the class bytecode. But you may also not want to propagate that information to runtime once you've weaved the aspects you need (for any reason, be it security, performance, information overhead...). – Baptiste Mathus Jun 13 '14 at 09:28
  • There is another use case for `CLASS`: Annotations that are only used at compile time, like Proguard's `@Keep` annotation used to exclude classes, methods from obfuscation. – RobertB Sep 04 '15 at 11:12
  • @RobertB wouldn't retention policy `SOURCE` be sufficient in that case? – Joffrey Nov 03 '17 at 11:01
  • it is said that **findbugs** offers some annotations with CLASS retention. – Tiina Jan 18 '18 at 09:12
  • IDEs use `CLASS` retention annotations all the time... – Lukas Eder Mar 31 '21 at 07:01
7

It looks like both are recorded into the bytecode and both may be accessed at the run-time anyway.

False for basic built-in annotation interfaces like getAnnotations. E.g.:

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.CLASS)
@interface RetentionClass {}

@Retention(RetentionPolicy.RUNTIME)
@interface RetentionRuntime {}

public static void main(String[] args) {
    @RetentionClass
    class C {}
    assert C.class.getAnnotations().length == 0;

    @RetentionRuntime
    class D {}
    assert D.class.getAnnotations().length == 1;
}

so the only way to observe a RetentionPolicy.CLASS annotation is by using a bytecode parser.

Another difference is that the Retention.CLASS annotated class gets a RuntimeInvisible class attribute, while Retention.RUNTIME annotations get a RuntimeVisible class attribute. This can be observed with javap.

Examples on GitHub for you to play with.

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
0

By default, annotations are not accessible through Reflection APIs. (RetentionPolicy.CLASS is the default retention policy)

You can specify for your custom annotation if it should be available at runtime, for inspection via reflection. You do so by annotating your annotation definition with the @Retention annotation.

Try this simple example

@Retention(RetentionPolicy.RUNTIME)
public @interface Version {
    int test();
}

@Version(test= 1)
public class Engineer{
   //code
}

public class Main {
        
    public static void main(String[] args) {
        Engineer engineer = new Engineer();
    
        Annotation[] annotations = engineer.getClass().getAnnotations();
        System.out.printf("%d annotations found.", annotations.length);
    }
}

Try to run the code again by changing the RetentionPolicy of the Version annotation to RetentionPolicy.CLASS and check the difference.

Yuresh Karunanayake
  • 519
  • 1
  • 4
  • 10