SONARJAVA-5295 Modify rule S6809: add support for @Cacheable (#4626)
This commit is contained in:
parent
2dc3a33c3b
commit
4bfe5a01d7
@ -1,16 +1,16 @@
|
|||||||
== Why is this an issue?
|
== 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.
|
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`).
|
or to handle the transaction (`@Transactional`).
|
||||||
However, when called using `this`, the proxy instance is bypassed, and the method is invoked directly
|
However, when called using `this`, the proxy instance is bypassed, and the method is invoked directly
|
||||||
without the required wrapper code.
|
without the required wrapper code.
|
||||||
|
|
||||||
== How to fix it
|
== 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`).
|
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.
|
The injected instance is a proxy on which the methods can be invoked safely.
|
||||||
|
|
||||||
@ -26,12 +26,19 @@ public class AsyncNotificationProcessor implements NotificationProcessor {
|
|||||||
@Override
|
@Override
|
||||||
public void process(Notification notification) {
|
public void process(Notification notification) {
|
||||||
processAsync(notification); // Noncompliant, call bypasses proxy
|
processAsync(notification); // Noncompliant, call bypasses proxy
|
||||||
|
retrieveNotification(notification.id); // Noncompliant, call bypasses proxy and will not be cached
|
||||||
}
|
}
|
||||||
|
|
||||||
@Async
|
@Async
|
||||||
public processAsync(Notification notification) {
|
public processAsync(Notification notification) {
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Cacheable
|
||||||
|
public Notification retrieveNotification(Long id) {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
@ -48,12 +55,18 @@ public class AsyncNotificationProcessor implements NotificationProcessor {
|
|||||||
@Override
|
@Override
|
||||||
public void process(Notification notification) {
|
public void process(Notification notification) {
|
||||||
asyncNotificationProcessor.processAsync(notification); // Compliant, call via injected proxy
|
asyncNotificationProcessor.processAsync(notification); // Compliant, call via injected proxy
|
||||||
|
asyncNotificationProcessor.retrieveNotification(notification.id); // Compliant, the call will be cached
|
||||||
}
|
}
|
||||||
|
|
||||||
@Async
|
@Async
|
||||||
public processAsync(Notification notification) {
|
public processAsync(Notification notification) {
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Cacheable
|
||||||
|
public Notification retrieveNotification(Long id) {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
@ -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/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/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
|
=== Articles & blog posts
|
||||||
|
|
||||||
- https://www.baeldung.com/spring-async[Baeldung - How To Do @Async in Spring]
|
- 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/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://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…
x
Reference in New Issue
Block a user