Skip to content

Commit f25d9b7

Browse files
SONARJAVA-4682 S6816: Nullable injected fields should provide a default value
1 parent e17b9ad commit f25d9b7

10 files changed

Lines changed: 451 additions & 3 deletions

File tree

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,15 +180,15 @@ public void javaCheckTestSources() throws Exception {
180180
softly.assertThat(newTotal).isEqualTo(knownTotal);
181181
softly.assertThat(rulesCausingFPs).hasSize(6);
182182
softly.assertThat(rulesNotReporting).hasSize(7);
183-
softly.assertThat(rulesSilenced).hasSize(81);
183+
softly.assertThat(rulesSilenced).hasSize(82);
184184

185185
/**
186186
* 4. Check total number of differences (FPs + FNs)
187187
*
188188
* No differences would mean that we find the same issues with and without the bytecode and libraries
189189
*/
190190
String differences = Files.readString(pathFor(TARGET_ACTUAL + PROJECT_KEY + "-no-binaries_differences"));
191-
softly.assertThat(differences).isEqualTo("Issues differences: 3579");
191+
softly.assertThat(differences).isEqualTo("Issues differences: 3594");
192192

193193
softly.assertAll();
194194
}

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2876,7 +2876,7 @@
28762876
{
28772877
"ruleKey": "S6804",
28782878
"hasTruePositives": false,
2879-
"falseNegatives": 9,
2879+
"falseNegatives": 11,
28802880
"falsePositives": 0
28812881
},
28822882
{
@@ -2909,6 +2909,12 @@
29092909
"falseNegatives": 5,
29102910
"falsePositives": 0
29112911
},
2912+
{
2913+
"ruleKey": "S6816",
2914+
"hasTruePositives": false,
2915+
"falseNegatives": 11,
2916+
"falsePositives": 0
2917+
},
29122918
{
29132919
"ruleKey": "S6817",
29142920
"hasTruePositives": false,
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package checks.spring;
2+
3+
class Constants {
4+
public static final String NON_COMPLIANT_PROPERTY_EXPRESSION_WITHOUT_NULLABLE_DEFAULT = "${myPropertyWithoutDefault}" ;
5+
private Constants() {
6+
/* No instance needed here */
7+
}
8+
}
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
package checks.spring;
2+
3+
import javax.annotation.CheckForNull;
4+
import javax.annotation.Nullable;
5+
import org.springframework.beans.factory.annotation.Value;
6+
7+
public class NullableInjectedFieldsHaveDefaultValueSample {
8+
@Nullable
9+
@Value("${my.property}") // Noncompliant [[sc=3;ec=27;secondary=-1]] {{Provide a default null value for this field.}}
10+
private String myProperty;
11+
12+
@Value("${my.property}") // Noncompliant [[sc=3;ec=27;secondary=+1]] {{Provide a default null value for this field.}}
13+
@Nullable
14+
private String myPropertyWithReversedAnnotations;
15+
16+
@Nullable
17+
@Value(value = "${my.property}") // Noncompliant [[sc=3;ec=35]]
18+
private String myOtherProperty;
19+
20+
@Nullable
21+
@Value("${my.property}") // Noncompliant [[sc=3;ec=27;quickfixes=literalfix]]
22+
private String myPropertyToFix;
23+
// fix@literalfix {{Set null as default value}}
24+
// edit@literalfix [[sc=10;ec=26]] {{"${my.property:#{null}}"}}
25+
26+
@Nullable
27+
@Value(value = "${my.property}") // Noncompliant [[sc=3;ec=35;quickfixes=argumentfix]]
28+
private String myPropertyToFixOnNamedArgument;
29+
// fix@argumentfix {{Set null as default value}}
30+
// edit@argumentfix [[sc=18;ec=34]] {{"${my.property:#{null}}"}}
31+
32+
public void foo(@Nullable @Value("${my.property}") String argument) { // Noncompliant [[sc=29;ec=53;secondary=+0]] {{Provide a default null value for this parameter.}}
33+
/* Do something */
34+
}
35+
36+
public void bar(@Value(value = "${my.property}") @Nullable String argument) { // Noncompliant [[sc=19;ec=51;secondary=+0]] {{Provide a default null value for this parameter.}}
37+
/* Do something */
38+
}
39+
40+
private static final String NON_COMPLIANT_IN_A_CONSTANT = "${non.compliant.constant}";
41+
//fix@fixStaticConstant {{Set null as default value}}
42+
//edit@fixStaticConstant [[sl=40;el=40;sc=61;ec=88]] {{"${non.compliant.constant:#{null}}"}}
43+
@Nullable
44+
@Value(value = NON_COMPLIANT_IN_A_CONSTANT) // Noncompliant [[sc=3;ec=46;secondary=-1;quickfixes=fixStaticConstant,localFixOnStaticConstant]]
45+
//fix@localFixOnStaticConstant {{Set null as default value locally}}
46+
//edit@localFixOnStaticConstant [[sc=18;ec=45]] {{"${non.compliant.constant:#{null}}"}}
47+
private String myNoncompliantIndirectProperty;
48+
49+
private final String finalButNotStatic = "${non.compliant.constant}";
50+
//fix@fixConstant {{Set null as default value}}
51+
//edit@fixConstant [[sl=49;el=49;sc=44;ec=71]] {{"${non.compliant.constant:#{null}}"}}
52+
@Nullable
53+
@Value(finalButNotStatic) // Noncompliant [[sc=3;ec=28;secondary=-1;quickfixes=fixConstant,localFixOnConstant]]
54+
// fix@localFixOnConstant {{Set null as default value locally}}
55+
//edit@localFixOnConstant [[sc=10;ec=27]] {{"${non.compliant.constant:#{null}}"}}
56+
private String myOtherNoncompliantIndirectProperty;
57+
58+
@Nullable
59+
@Value(Constants.NON_COMPLIANT_PROPERTY_EXPRESSION_WITHOUT_NULLABLE_DEFAULT) // Noncompliant [[sc=3;ec=79;quickfixes=fixEternal]]
60+
// fix@fixEternal {{Set null as default value locally}}
61+
// edit@fixEternal [[sc=10;ec=78]] {{"${myPropertyWithoutDefault:#{null}}"}}
62+
private String resolvableButForeignConstant;
63+
64+
private static final String DEFINED_IN_A_CONSTANT = "${my.constant:#{null}}";
65+
@Nullable
66+
@Value(value = DEFINED_IN_A_CONSTANT) // Compliant
67+
private String myCompliantIndirectProperty;
68+
69+
private String myNonCompliantAttribute;
70+
71+
@Value("${my.property}") // Noncompliant [[sc=3;ec=27;secondary=+1]]
72+
public void setMyNonCompliantAttribute(@Nullable String myNonCompliantAttribute) {
73+
this.myNonCompliantAttribute = myNonCompliantAttribute;
74+
}
75+
76+
@Nullable
77+
@Value(value = DEFINED_IN_A_CONSTANT) // Compliant
78+
private String myOtherCompliantIndirectProperty;
79+
80+
@Nullable
81+
@Value("myProperty") // Compliant for S6816, even if wrong by other rules
82+
private String myPropertyNotUsingSpEL;
83+
84+
@Nullable
85+
@Value("${myProperty") // Compliant for S6816, even if wrong by other rules
86+
private String myPropertyWithBrokenSpEL;
87+
88+
@Nullable
89+
@Value("${my.property:#{null}}") // Compliant, a default value is provided
90+
private String myCompliantProperty;
91+
92+
@Value(value = "${my.property}") // Compliant, the field is not nullable
93+
private String myNonNullProperty;
94+
95+
@Value("#{null}")
96+
@Nullable
97+
private String nullAnyway;
98+
99+
100+
private String myCompliantAttribute;
101+
102+
@Value("${my.property:#{null}}") // Compliant
103+
public void setMyCompliantAttribute(@Nullable String myCompliantAttribute) {
104+
this.myCompliantAttribute = myCompliantAttribute;
105+
}
106+
107+
@CheckForNull
108+
private String setNothing(@Nullable String useless) {
109+
return useless;
110+
}
111+
112+
@Value("${my.property}") // Compliant not a setter
113+
private String setNothingWithTwoParameters(@Nullable String a, String b) {
114+
a = b;
115+
return a;
116+
}
117+
}

java-checks/src/main/java/org/sonar/java/checks/CheckList.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@
146146
import org.sonar.java.checks.spring.FieldDependencyInjectionCheck;
147147
import org.sonar.java.checks.spring.ModelAttributeNamingConventionForSpELCheck;
148148
import org.sonar.java.checks.spring.NonSingletonAutowiredInSingletonCheck;
149+
import org.sonar.java.checks.spring.NullableInjectedFieldsHaveDefaultValueCheck;
149150
import org.sonar.java.checks.spring.OptionalRestParametersShouldBeObjectsCheck;
150151
import org.sonar.java.checks.spring.PersistentEntityUsedAsRequestParameterCheck;
151152
import org.sonar.java.checks.spring.RequestMappingMethodPublicCheck;
@@ -524,6 +525,7 @@ public final class CheckList {
524525
NonShortCircuitLogicCheck.class,
525526
NonStaticClassInitializerCheck.class,
526527
NotifyCheck.class,
528+
NullableInjectedFieldsHaveDefaultValueCheck.class,
527529
NullCheckWithInstanceofCheck.class,
528530
NullReturnedOnComputeIfPresentOrAbsentCheck.class,
529531
OSCommandsPathCheck.class,

0 commit comments

Comments
 (0)