Skip to content

Commit 34326b0

Browse files
SONARJAVA-5324 @PathVariable must have path template placeholder (#5016)
1 parent 1c58437 commit 34326b0

7 files changed

Lines changed: 573 additions & 232 deletions

File tree

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"ruleKey": "S3752",
33
"hasTruePositives": true,
4-
"falseNegatives": 23,
4+
"falseNegatives": 25,
55
"falsePositives": 0
6-
}
6+
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"ruleKey": "S6856",
33
"hasTruePositives": false,
4-
"falseNegatives": 23,
4+
"falseNegatives": 43,
55
"falsePositives": 0
66
}

java-checks-test-sources/default/src/main/java/checks/MissingPathVariableAnnotationCheckSample.java renamed to java-checks-test-sources/default/src/main/java/checks/spring/MissingPathVariableAnnotationCheckSample.java

Lines changed: 80 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package checks;
1+
package checks.spring;
22

33
import java.util.Map;
44
import java.util.Optional;
@@ -8,6 +8,7 @@
88
import org.springframework.web.bind.annotation.PathVariable;
99
import org.springframework.web.bind.annotation.PostMapping;
1010
import org.springframework.web.bind.annotation.PutMapping;
11+
import org.springframework.web.bind.annotation.RequestMapping;
1112

1213
public class MissingPathVariableAnnotationCheckSample {
1314

@@ -24,13 +25,13 @@ public void handle(@PathVariable String name, @PathVariable String version, @Pat
2425

2526

2627

27-
@GetMapping("/{id}") // Noncompliant {{Bind path variable "id" to a method parameter.}}
28+
@GetMapping("/{id}") // Noncompliant {{Bind template variable "id" to a method parameter.}}
2829
//^^^^^^^^^^^^^^^^^^^^
2930
public String get(String id) {
3031
return "Hello World";
3132
}
3233

33-
@PostMapping(value = "/{name}") // Noncompliant {{Bind path variable "name" to a method parameter.}}
34+
@PostMapping(value = "/{name}") // Noncompliant {{Bind template variable "name" to a method parameter.}}
3435
public String post(String id) {
3536
return "Hello World";
3637
}
@@ -45,6 +46,11 @@ public String delete(String id) {
4546
return "Hello World";
4647
}
4748

49+
@RequestMapping("/{id}") // Noncompliant
50+
public String request(String id) {
51+
return "Hello World";
52+
}
53+
4854
@PutMapping("/id")
4955
@DeleteMapping("/{id}") // Noncompliant
5056
public String deletePut(String id) {
@@ -73,12 +79,22 @@ public String deleteCompliant(@PathVariable String id) { // compliant
7379
return "Hello World";
7480
}
7581

82+
@RequestMapping("/{id}")
83+
public String requestCompliant(@PathVariable String id) {
84+
return "Hello World";
85+
}
86+
7687
@GetMapping("/{id}")
7788
@DeleteMapping({"/{id}"})
7889
public String deleteGetCompliant(@PathVariable String id) { // compliant
7990
return "Hello World";
8091
}
8192

93+
@interface NotRequestMappingAnnotation {}
94+
95+
@NotRequestMappingAnnotation
96+
public void notAnnotatedWithRequestMapping(){}
97+
8298
@GetMapping("/{id}")
8399
public String getOtherThanString(@PathVariable Integer id) { // compliant
84100
return "Hello World";
@@ -100,7 +116,7 @@ public String get2PathVariables(@PathVariable String id, @PathVariable String na
100116
}
101117

102118
@GetMapping("/{id}") // Noncompliant
103-
public String getBadName(@PathVariable String a) {
119+
public String getBadName(@PathVariable String a) { // Noncompliant
104120
return "Hello World";
105121
}
106122

@@ -153,7 +169,7 @@ public String withoutAnnotation(String id) { // compliant
153169
return "Hello World";
154170
}
155171

156-
public String withoutRequestMappingAnnotation(@PathVariable String id) { // compliant
172+
public String withoutRequestMappingAnnotation(@PathVariable String id) { // Noncompliant
157173
return "Hello World";
158174
}
159175

@@ -191,15 +207,20 @@ public String getCrazyPathNonCompliant(String id) {
191207
return "Hello World";
192208
}
193209

194-
@GetMapping("/{id}/{xxx${placeHolder}xxxx}/{${{placeHolder}}}")
195-
public String getPlaceHolder(String id) { // compliant, we don't consider this case
210+
@GetMapping("/{id}/{a:${placeHolder}xxxx}/{b:${{placeHolder}}}")
211+
public String getPlaceHolder(@PathVariable String id, @PathVariable String a, @PathVariable String b) {
196212
return "Hello World";
197213
}
198214

199215
static class ModelA {
200216
@ModelAttribute("user")
201-
public String getUser(@PathVariable String id, @PathVariable String name) {
202-
return "user";
217+
public String getUser(@PathVariable String id, @PathVariable String name) { // always compliant when method annotated with @ModelAttribute
218+
return "user"; // because the case is too complex to handle
219+
}
220+
221+
@ModelAttribute("empty")
222+
public String emptyModel(String notPathVariable){
223+
return "";
203224
}
204225

205226
@GetMapping("/{id}/{name}")
@@ -213,7 +234,7 @@ public String get2(@PathVariable String age) { // compliant
213234
return "Hello World";
214235
}
215236

216-
@GetMapping("/{id}/{name}/{age}") // Noncompliant {{Bind path variable "age" to a method parameter.}}
237+
@GetMapping("/{id}/{name}/{age}") // Noncompliant {{Bind template variable "age" to a method parameter.}}
217238
public String get3() {
218239
return "Hello World";
219240
}
@@ -246,4 +267,53 @@ public String get3() {
246267
}
247268
}
248269

270+
271+
@GetMapping("/a/path")
272+
public String pathVariableWithoutParameter(@PathVariable String aVar){ // Noncompliant {{Bind method parameter "aVar" to a template variable.}}
273+
// ^^^^^^^^^^^^^^^^^^^^^^^^^
274+
return "";
275+
}
276+
277+
@GetMapping("/a/path/{aVar1}")
278+
public String twoPathVariables(@PathVariable String aVar1, @PathVariable String aVar2){ // Noncompliant
279+
// ^^^^^^^^^^^^^^^^^^^^^^^^^^
280+
return "";
281+
}
282+
283+
@GetMapping("/a/path")
284+
public String pathVariableWithValue(@PathVariable(value = "aVar") String foo){ // Noncompliant
285+
return "";
286+
}
287+
288+
@GetMapping("/a/path")
289+
public String pathVariableWithName(@PathVariable(name = "aVar") String foo){ // Noncompliant
290+
return "";
291+
}
292+
293+
@GetMapping("/a/path")
294+
public String pathVariableWithDefault(@PathVariable("aVar") String foo){ // Noncompliant
295+
return "";
296+
}
297+
298+
@GetMapping("/a/path")
299+
public String pathVariableEmptyName(@PathVariable("") String foo){ // Noncompliant
300+
return "";
301+
}
302+
303+
@RequestMapping("/path/{id}")
304+
static class Controller {
305+
void fromRequestMapping(@PathVariable String id){}
306+
307+
@GetMapping("/{age}")
308+
void fromBoth(@PathVariable String id, @PathVariable int age){}
309+
310+
@GetMapping()
311+
void missingTemplateParameter(@PathVariable String missing){} // Noncompliant
312+
}
313+
314+
@RequestMapping()
315+
static class EmptyRequestMapping {}
316+
317+
@RequestMapping("/{age")
318+
static class WrongPathRequestMapping {}
249319
}

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

Lines changed: 0 additions & 186 deletions
This file was deleted.

0 commit comments

Comments
 (0)