Skip to content

Commit a02adef

Browse files
SONARJAVA-4651 extend rule S2230 with @Asynch annotations (#4484)
1 parent 9f2239c commit a02adef

5 files changed

Lines changed: 47 additions & 15 deletions

File tree

its/ruling/src/test/java/org/sonar/java/it/AutoScanTest.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,6 @@
5252
import org.slf4j.Logger;
5353
import org.slf4j.LoggerFactory;
5454

55-
import static org.assertj.core.api.Assertions.assertThat;
56-
5755
public class AutoScanTest {
5856

5957
private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();
@@ -190,7 +188,7 @@ public void javaCheckTestSources() throws Exception {
190188
* No differences would mean that we find the same issues with and without the bytecode and libraries
191189
*/
192190
String differences = Files.readString(pathFor(TARGET_ACTUAL + PROJECT_KEY + "-no-binaries_differences"));
193-
softly.assertThat(differences).isEqualTo("Issues differences: 3430");
191+
softly.assertThat(differences).isEqualTo("Issues differences: 3446");
194192

195193
softly.assertAll();
196194
}

its/ruling/src/test/resources/autoscan/autoscan-diff-by-rules.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1112,7 +1112,7 @@
11121112
{
11131113
"ruleKey": "S2230",
11141114
"hasTruePositives": true,
1115-
"falseNegatives": 0,
1115+
"falseNegatives": 15,
11161116
"falsePositives": 0
11171117
},
11181118
{
@@ -2882,7 +2882,7 @@
28822882
{
28832883
"ruleKey": "S6810",
28842884
"hasTruePositives": false,
2885-
"falseNegatives": 5,
2885+
"falseNegatives": 6,
28862886
"falsePositives": 0
28872887
},
28882888
{

java-checks-test-sources/src/main/files/non-compiling/checks/spring/TransactionalMethodVisibilityCheck.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@
55
class TransactionalMethodVisibilityCheck {
66
// Cannot compile because a Transactional method should be overridable
77
@org.springframework.transaction.annotation.Transactional
8-
private void privateTransactionalMethod() {} // Noncompliant [[sc=16;ec=42]] {{Make this method "public" or remove the "@Transactional" annotation}}
8+
private void privateTransactionalMethod() {} // Noncompliant [[sc=16;ec=42]] {{Make this method "public" or remove the "@Transactional" annotation.}}
99

1010
// Cannot compile because a Transactional method should be overridable
1111
@Transactional
12-
private void privateTransactionalMethodWithImportBasedAnnotation() {} // Noncompliant {{Make this method "public" or remove the "@Transactional" annotation}}
12+
private void privateTransactionalMethodWithImportBasedAnnotation() {} // Noncompliant {{Make this method "public" or remove the "@Transactional" annotation.}}
1313

1414
@org.xxx.Transactional
1515
private void privateMethodWithNonSpringAnnotation() {} // Compliant
Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package checks.spring;
22

3+
import java.util.concurrent.Future;
4+
import org.springframework.scheduling.annotation.Async;
35
import org.springframework.transaction.annotation.Transactional;
46

5-
class TransactionalMethodVisibilityCheck {
7+
abstract class TransactionalMethodVisibilityCheck {
68

79
public interface C {
810
@Transactional
@@ -13,13 +15,32 @@ private interface B {
1315
@Transactional
1416
int bar(); // Compliant
1517
}
16-
18+
19+
private interface A {
20+
@Async
21+
int bar(); // Compliant
22+
}
23+
24+
@Async
25+
protected abstract Future<String> aMethod(); // Noncompliant
26+
27+
28+
@Async
29+
public Future<String> asyncMethod(){ // compliant
30+
return null;
31+
}
32+
33+
@Async
34+
private Future<String> asyncMethodPrivate(){ // Noncompliant {{Make this method "public" or remove the "@Async" annotation.}}
35+
return null;
36+
}
37+
1738
@org.springframework.transaction.annotation.Transactional
1839
public void publicTransactionalMethod() {} // Compliant
1940

2041
@org.springframework.transaction.annotation.Transactional
21-
protected void protectedTransactionalMethod() {} // Noncompliant {{Make this method "public" or remove the "@Transactional" annotation}}
42+
protected void protectedTransactionalMethod() {} // Noncompliant [[sc=18;ec=46]] {{Make this method "public" or remove the "@Transactional" annotation.}}
2243

2344
@org.springframework.transaction.annotation.Transactional
24-
void defaultVisibilityTransactionalMethod() {} // Noncompliant {{Make this method "public" or remove the "@Transactional" annotation}}
45+
void defaultVisibilityTransactionalMethod() {} // Noncompliant {{Make this method "public" or remove the "@Transactional" annotation.}}
2546
}

java-checks/src/main/java/org/sonar/java/checks/spring/TransactionalMethodVisibilityCheck.java

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
import java.util.Collections;
2323
import java.util.List;
24+
import java.util.Map;
2425
import org.sonar.check.Rule;
2526
import org.sonar.plugins.java.api.IssuableSubscriptionVisitor;
2627
import org.sonar.plugins.java.api.tree.AnnotationTree;
@@ -30,6 +31,14 @@
3031
@Rule(key = "S2230")
3132
public class TransactionalMethodVisibilityCheck extends IssuableSubscriptionVisitor {
3233

34+
private static final List<String> proxyAnnotations = List.of(
35+
"org.springframework.transaction.annotation.Transactional",
36+
"org.springframework.scheduling.annotation.Async");
37+
38+
private static final Map<String, String> annShortName = Map.of(
39+
"org.springframework.transaction.annotation.Transactional", "@Transactional",
40+
"org.springframework.scheduling.annotation.Async", "@Async");
41+
3342
@Override
3443
public List<Tree.Kind> nodesToVisit() {
3544
return Collections.singletonList(Tree.Kind.METHOD);
@@ -38,14 +47,18 @@ public List<Tree.Kind> nodesToVisit() {
3847
@Override
3948
public void visitNode(Tree tree) {
4049
MethodTree method = (MethodTree) tree;
41-
if (!method.symbol().isPublic() && hasTransactionalAnnotation(method)) {
42-
reportIssue(method.simpleName(), "Make this method \"public\" or remove the \"@Transactional\" annotation");
50+
if (!method.symbol().isPublic()) {
51+
proxyAnnotations.stream()
52+
.filter(annSymbol -> hasAnnotation(method, annSymbol))
53+
.forEach(annSymbol -> reportIssue(
54+
method.simpleName(),
55+
"Make this method \"public\" or remove the \"" + annShortName.get(annSymbol) + "\" annotation."));
4356
}
4457
}
4558

46-
private static boolean hasTransactionalAnnotation(MethodTree method) {
59+
private static boolean hasAnnotation(MethodTree method, String annotationSymbol) {
4760
for (AnnotationTree annotation : method.modifiers().annotations()) {
48-
if (annotation.symbolType().is("org.springframework.transaction.annotation.Transactional")) {
61+
if (annotation.symbolType().is(annotationSymbol)) {
4962
return true;
5063
}
5164
}

0 commit comments

Comments
 (0)