rspec/rules/S2109/java/rule.adoc

66 lines
2.6 KiB
Plaintext

== Why is this an issue?
Denoted by the "@" symbol, annotations are metadata that can be added to classes, methods, and variables for various
purposes such as documentation, code analysis, and runtime processing.
Annotations have retention policies that determine in which context they are retained and available for use.
There are three retention policies for annotations:
* `RetentionPolicy.SOURCE` - Annotations are only available during compilation and code analysis.
They are not included in the compiled class file and are not available at runtime.
E.G. `@Override`, `@SuppressWarnings`
* `RetentionPolicy.CLASS` - Annotations are included in the compiled class file providing information to the compiler,
but they are not retained by the JVM at runtime. This is the default retention policy. E.G. `@PreviewFeature`
* `RetentionPolicy.RUNTIME` - Annotations are included in the compiled class file and available at runtime.
They can be accessed and used by the program through reflection.
E.G. `@FunctionalInterface`, `@Deprecated`
It is important to understand that only annotations having the `RUNTIME` retention policy can be accessed at runtime
using reflection. For example, the following if condition is true when the method argument is the
`java.util.function.Function` class:
[source,java]
----
void execute(Class<?> cls) {
if (cls.isAnnotationPresent(FunctionalInterface.class)) {
// ...
}
}
----
Therefore, it is an issue to use reflection in combination with annotations with the `SOURCE` or `CLASS` retention policy because they
are not present at runtime. For example, in the JVM source code, the `hashCode()` method of the `Integer` class has
the `@Override` annotation. However, the following if condition will always be false even if the method argument is the
`Integer#hashCode()` method because `@Override` has the `SOURCE` retention policy:
[source,java]
----
void execute(Method method) {
if (method.isAnnotationPresent(Override.class)) { // Noncompliant, if condition will always be false because
// @Override is declared with @Retention(RetentionPolicy.SOURCE)
// ...
}
}
----
This rule detects improper reflective access on annotations having the `SOURCE` or `CLASS` retention policy.
== Resources
=== Documentation
* https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/annotation/RetentionPolicy.html[Oracle SDK - java.lang.annotation.RetentionPolicy]
ifdef::env-github,rspecator-view[]
'''
== Implementation Specification
(visible only on this page)
=== Message
"@xxx" is not available at runtime and cannot be seen with reflection.
endif::env-github,rspecator-view[]