Skip to content

SONARJAVA-5295 Modify rule S6809: add support for @Cacheable #4626

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 28, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 18 additions & 3 deletions rules/S6809/java/rule.adoc
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
== Why is this an issue?

A method annotated with Spring's `@Async` or `@Transactional` annotations will not work as expected
A method annotated with Spring's `@Async`, `@Cacheable` or `@Transactional` annotations will not work as expected
if invoked directly from within its class.

This is because Spring generates a proxy class with wrapper code to manage the method's asynchronicity (`@Async`)
This is because Spring generates a proxy class with wrapper code to manage the method's asynchronicity (`@Async`), to cache methods invocations (`@Cacheable`),
or to handle the transaction (`@Transactional`).
However, when called using `this`, the proxy instance is bypassed, and the method is invoked directly
without the required wrapper code.

== How to fix it

Replace calls to `@Async` or `@Transactional` methods via `this`
Replace calls to `@Async`, `@Cacheable` or `@Transactional` methods via `this`
with calls on an instance that was injected by Spring (`@Autowired`, `@Resource` or `@Inject`).
The injected instance is a proxy on which the methods can be invoked safely.

Expand All @@ -26,12 +26,19 @@ public class AsyncNotificationProcessor implements NotificationProcessor {
@Override
public void process(Notification notification) {
processAsync(notification); // Noncompliant, call bypasses proxy
retrieveNotification(notification.id); // Noncompliant, call bypasses proxy and will not be cached
}

@Async
public processAsync(Notification notification) {
// ...
}

@Cacheable
public Notification retrieveNotification(Long id) {
// ...
}

}
----

Expand All @@ -48,12 +55,18 @@ public class AsyncNotificationProcessor implements NotificationProcessor {
@Override
public void process(Notification notification) {
asyncNotificationProcessor.processAsync(notification); // Compliant, call via injected proxy
asyncNotificationProcessor.retrieveNotification(notification.id); // Compliant, the call will be cached
}

@Async
public processAsync(Notification notification) {
// ...
}

@Cacheable
public Notification retrieveNotification(Long id) {
// ...
}
}
----

Expand All @@ -63,9 +76,11 @@ public class AsyncNotificationProcessor implements NotificationProcessor {

- https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/scheduling/annotation/Async.html[Spring Framework API - Annotation Interface Async]
- https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/transaction/annotation/Transactional.html[Spring Framework API - Annotation Interface Transactional]
- https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/cache/annotation/Cacheable.html[Spring Framework API - Annotation Interface Cacheable]

=== Articles & blog posts

- https://www.baeldung.com/spring-async[Baeldung - How To Do @Async in Spring]
- https://stackoverflow.com/questions/22561775/spring-async-ignored[Stack Overflow - Spring @Async ignored]
- https://stackoverflow.com/questions/4396284/does-spring-transactional-attribute-work-on-a-private-method[Stack Overflow - Does Spring @Transactional attribute work on a private method?]
- https://docs.spring.io/spring-framework/reference/integration/cache/annotations.html#cache-annotations-cacheable[Spring docs, The @Cacheable Annotation]
Loading