How do different retention policies affect my annotations?
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')
RetentionPolicy CLASS vs. RUNTIME
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.
Java Annotations - looking for an example of RetentionPolicy.CLASS
Of all of the large number of libraries I have in my current project. the only examples I can find are in the Google Guava library, for example com.google.common.annotations.GwtCompatible
.
I'm not really sure why they chose this retention policy, though - perhaps for tools support, where the tools read the class files themselves, rather than going through the reflection API. I'm not sure that I really see the point of this distinction, though.
Configuring Annotations to be RUNTIME Retention By Default (without individual @Retention)
The Java Language Specification, section 9.6.4.2. @Retention states:
If T does not have a (meta-)annotation
m
that corresponds tojava.lang.annotation.Retention
, then a Java compiler must treat T as if it does have such a meta-annotationm
with an element whose value isjava.lang.annotation.RetentionPolicy.CLASS
.
As you can see, it is a strict requirement that missing annotation is same as @Retention(RetentionPolicy.CLASS)
.
If you need @Retention(RetentionPolicy.RUNTIME)
, then you must explicitly specify that.
Can't see annotations via reflection despite RetentionPolicy being RUNTIME
Due to the @PreAuthorize
annotation you don't get the actual class but a proxied instance of that class. As annotations aren't inherited (by design in the language) you won't see them.
I suggest to do 2 things, first use the AopProxyUtils.ultimateTargetClass
to get the actual class of the bean and second use the AnnotationUtils
to get the annotation from the class.
Map<String, Object> beans = appContext.getBeansWithAnnotation(RestController.class);
for (Map.Entry<String, Object> entry : beans.entrySet()) {
Class clazz = AopProxyUtils. AopProxyUtils.ultimateTargetClass(entry.getValue());
ReflectionUtils.doWithMethods(clazz, new MethodCallback() {
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
Annotation[] annotations = AnnotationUtils.getAnnotations(method);
for(Annotation annotation : annotations) {
LOG.debug("Annotation: " + annotation);
}
}
});
}
Something like that should do the trick, also some cleanup using the Spring provided utility classes.
Explanation about Annotations
Annotations are more flexible in terms
of how you use them, with options for
whether the annotation information is
to be included in class files output
by the compiler and made available to
the application at run time
This, I think, refers to the fact that Java5 annotations can be dropped by the compiler, whereas some can be retained in the bytecode. This is controlled by the @Retention
annotation that is placed on your annotation type, e.g
@Documented
@Retention(value=RUNTIME)
public @interface Deprecated
This indicates that the @Deprecated
annotation will be present in the bytecode, and will also be visible to reflection. java.lang.annotation.RetentionPolicy
defines the different options.
Related Topics
Differencebetween @Inject and @Autowired in Spring Framework? Which One to Use Under What Condition
How to Call the Overridden Method of a Superclass
Why I Can't Create an Array with Large Size
Capturing Image from Webcam in Java
Printing Java Collections Nicely (Tostring Doesn't Return Pretty Output)
"Detached Entity Passed to Persist Error" with JPA/Ejb Code
What Happens When You Increment an Integer Beyond Its Max Value
Why Use a Reentrantlock If One Can Use Synchronized(This)
@Aspectj Pointcut for All Methods of a Class with Specific Annotation
Compile-Time Constants and Variables
How Is Hashcode() Calculated in Java
How to Add Unicode in Truetype0Font on PDFbox 2.0.0
How to Simulate a Buffered Peripheral Device with Swingworker
Log4J: Log Output of a Specific Class to a Specific Appender