Skip to content

Commit f106053

Browse files
SONARJAVA-4653 Fix ClassCastException and FPs (#4495)
1 parent 6dbbe3f commit f106053

2 files changed

Lines changed: 36 additions & 7 deletions

File tree

java-checks-test-sources/src/main/java/checks/spring/OptionalRestParametersShouldBeObjects.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,26 @@ public Article getArticleButSettingADifferentValue(@PathVariable(name = "article
5656
return new Article(articleId);
5757
}
5858

59+
@GetMapping(value = "{/article/id")
60+
public Article getArticleRequestParamWithDefaultValue(@RequestParam(required = false, defaultValue = "1") int articleId) { // Compliant
61+
return new Article(articleId);
62+
}
63+
5964
@GetMapping(value = {"/article/{id}"})
6065
public Article getArticleButDifferentlyAnnotated(@Nullable int articleId) { // Compliant
6166
return new Article(articleId);
6267
}
6368

69+
@GetMapping(value = {"/article/{id}"})
70+
public Article getArticlePathVariableWithValue(@PathVariable("id") int articleId) { // Compliant
71+
return new Article(articleId);
72+
}
73+
74+
@GetMapping(value = {"/article/{id}"})
75+
public Article getArticleRequestParamWithValue(@RequestParam("id") int articleId) { // Compliant
76+
return new Article(articleId);
77+
}
78+
6479
record Article(int id) {
6580
}
6681
}

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

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
package org.sonar.java.checks.spring;
2121

2222
import java.util.List;
23+
import java.util.stream.Stream;
2324
import org.sonar.check.Rule;
2425
import org.sonar.plugins.java.api.IssuableSubscriptionVisitor;
2526
import org.sonar.plugins.java.api.tree.AnnotationTree;
@@ -31,10 +32,11 @@
3132

3233
@Rule(key = "S6814")
3334
public class OptionalRestParametersShouldBeObjectsCheck extends IssuableSubscriptionVisitor {
34-
35+
private static final String PATH_VARIABLE_ANNOTATION = "org.springframework.web.bind.annotation.PathVariable";
36+
private static final String REQUEST_PARAM_ANNOTATION = "org.springframework.web.bind.annotation.RequestParam";
3537
private static final List<String> PARAMETER_ANNOTATIONS = List.of(
36-
"org.springframework.web.bind.annotation.PathVariable",
37-
"org.springframework.web.bind.annotation.RequestParam"
38+
PATH_VARIABLE_ANNOTATION,
39+
REQUEST_PARAM_ANNOTATION
3840
);
3941

4042
@Override
@@ -53,17 +55,29 @@ public void visitNode(Tree tree) {
5355
private static boolean isOptionalPrimitive(VariableTree parameter) {
5456
return parameter.type().symbolType().isPrimitive() &&
5557
parameter.modifiers().annotations().stream()
56-
.anyMatch(OptionalRestParametersShouldBeObjectsCheck::isMarkingAsOptional);
58+
.anyMatch(annotation -> isMarkingAsOptional(annotation) && !hasDefaultValue(annotation));
5759
}
5860

5961
private static boolean isMarkingAsOptional(AnnotationTree annotation) {
6062
return PARAMETER_ANNOTATIONS.stream().anyMatch(candidate -> annotation.annotationType().symbolType().is(candidate)) &&
61-
annotation.arguments().stream().anyMatch(expressionTree -> {
62-
// Because all parameters of the supported annotations are assignments, we can cast safely here.
63-
AssignmentExpressionTree assignment = (AssignmentExpressionTree) expressionTree;
63+
streamAllNamedArguments(annotation).anyMatch(assignment -> {
6464
IdentifierTree variable = (IdentifierTree) assignment.variable();
6565
Boolean constant = assignment.expression().asConstant(Boolean.class).orElse(Boolean.TRUE);
6666
return "required".equals(variable.name()) && Boolean.FALSE.equals(constant);
6767
});
6868
}
69+
70+
private static boolean hasDefaultValue(AnnotationTree annotation) {
71+
return annotation.annotationType().symbolType().is(REQUEST_PARAM_ANNOTATION) &&
72+
streamAllNamedArguments(annotation).anyMatch(assignment -> {
73+
IdentifierTree variable = (IdentifierTree) assignment.variable();
74+
return "defaultValue".equals(variable.name());
75+
});
76+
}
77+
78+
private static Stream<AssignmentExpressionTree> streamAllNamedArguments(AnnotationTree annotation) {
79+
return annotation.arguments().stream()
80+
.filter(expression -> expression.is(Tree.Kind.ASSIGNMENT))
81+
.map(AssignmentExpressionTree.class::cast);
82+
}
6983
}

0 commit comments

Comments
 (0)