Skip to content

Commit 85f296e

Browse files
SONARJAVA-4917 S6857: support property placeholder inside SpEL (#5128)
1 parent 6a4bfa0 commit 85f296e

3 files changed

Lines changed: 244 additions & 137 deletions

File tree

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"ruleKey": "S6857",
33
"hasTruePositives": false,
4-
"falseNegatives": 63,
4+
"falseNegatives": 64,
55
"falsePositives": 0
66
}

java-checks-test-sources/default/src/main/java/checks/spring/SpelExpressionCheckSample.java

Lines changed: 51 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package checks.spring;
22

33
import java.util.List;
4+
import java.util.Map;
45
import org.springframework.beans.factory.annotation.Value;
56
import org.springframework.data.mongodb.repository.Query;
67
import org.springframework.data.repository.query.Param;
@@ -14,6 +15,7 @@ public class SpelExpressionCheckSample {
1415
private static final String INVALID_PROPERTY_PLACEHOLDER = "${foo.bar[}";
1516
private static final String VALID_PROPERTY_PLACEHOLDER = "${foo.bar}";
1617

18+
1719
@Value(UNCLOSED) // Noncompliant {{Add missing '}' for this property placeholder or SpEL expression.}}
1820
// ^^^^^^^^
1921
private String complexArgument1;
@@ -100,15 +102,15 @@ public class SpelExpressionCheckSample {
100102
@Value("${user.region:#{'D'+'E'}}") // Compliant
101103
private String default10;
102104

103-
@Value("${user.region:#{null}:#{null}:foo.bar}") // Noncompliant
105+
@Value("${user.region:#{null}:#{null}:foo.bar}") // Compliant
104106
private String default11;
105107

106-
@Value("${user.region:#{null}:#{4**4}:foo.bar}") // Noncompliant {{Correct this malformed property placeholder.}}
107-
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
108+
@Value("${user.region:#{null}:#{4**4}:foo.bar}") // Noncompliant {{Correct this malformed SpEL expression.}}
109+
// ^^^^^^^
108110
private String default12;
109111

110112
@Value("${user.region:#{4**4}:#{null}:foo.bar}") // Noncompliant {{Correct this malformed SpEL expression.}}
111-
// ^^^^^^^
113+
112114
private String default13;
113115

114116
@Value("${user.2region:default-region}") // Compliant
@@ -441,4 +443,49 @@ public static class RequestController2 { }
441443
private String sonarJava5079DefaultValueContainsColon2;
442444

443445
private static final String MOCKED_SOAP_SP_CLIENT_SSL = "classpath:mocked-soap-sp-client-ssl.jks";
446+
447+
static class PropertyPlaceHolderInsideSpEL {
448+
// We want to parse correctly the expression below
449+
@Value("#{${placeholder}}") // Compliant
450+
private Map<String, Integer> placeholderStage1;
451+
452+
// However, the problem is that Spring evaluates the expression in two stages
453+
// 1. it parses the property placeholders and substitutes them
454+
// 2. it parses the SpEL expression and executes it
455+
456+
// After evaluating the property placeholder, we have the following expression
457+
@Value("#{{key1: '1', key2: '2', key3: '3'}}") // Compliant
458+
private Map<String, Integer> SpELStage1;
459+
460+
// It is easy to validate that property placeholders are valid, but without the context we cannot validate the spring expression
461+
// A solution is to use clever values to replace the property placeholders for instance replace "${placeholder}" with "#aVar"
462+
@Value("#{${placeholder}}") // Compliant
463+
private Integer placeholderStage2;
464+
@Value("#{#aVar}") // Compliant
465+
private Integer SpELStage2;
466+
467+
// However, it is not possible to find a value that is valid in all the cases.
468+
// "#aVar" does not work in the case below.
469+
@Value("#{@${placeholder}}") // Compliant
470+
private Integer placeholderStage3;
471+
// "@#aVar" is not a valid SpEL expression.
472+
@Value("#{@#aVar}") // Noncompliant
473+
private Integer SpELStage3;
474+
475+
@Value("#{@${placeholder}}") // Compliant
476+
private Integer placeholderStage4;
477+
@Value("#{@aBean}") // Compliant
478+
private Integer SpELStage4;
479+
480+
@Value("#{${placeholder:10}}") // Compliant
481+
private Integer placeholderStage5;
482+
@Value("#{10}") // Compliant
483+
private Integer SpELStage5;
484+
485+
486+
@Value("#{@${placeholder:10}}") // Compliant
487+
private Integer placeholderStage6;
488+
@Value("#{@10}") // Noncompliant
489+
private Integer SpELStage6;
490+
}
444491
}

0 commit comments

Comments
 (0)