2020package org .sonar .java .checks .spring ;
2121
2222import java .util .List ;
23+ import java .util .stream .Stream ;
2324import org .sonar .check .Rule ;
2425import org .sonar .plugins .java .api .IssuableSubscriptionVisitor ;
2526import org .sonar .plugins .java .api .tree .AnnotationTree ;
3132
3233@ Rule (key = "S6814" )
3334public 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