-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Codemod created for migrating RequestMapping to shortcut annotations on verbose cases. --------- Co-authored-by: Arshan Dabirsiaghi <[email protected]>
- Loading branch information
1 parent
4eee3b6
commit f4db05e
Showing
7 changed files
with
265 additions
and
0 deletions.
There are no files selected for viewing
65 changes: 65 additions & 0 deletions
65
core-codemods/src/main/java/io/codemodder/codemods/VerboseRequestMappingCodemod.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
package io.codemodder.codemods; | ||
|
||
import static io.codemodder.ast.ASTTransforms.addImportIfMissing; | ||
|
||
import com.contrastsecurity.sarif.Result; | ||
import com.github.javaparser.ast.CompilationUnit; | ||
import com.github.javaparser.ast.expr.MemberValuePair; | ||
import com.github.javaparser.ast.expr.NormalAnnotationExpr; | ||
import io.codemodder.*; | ||
import io.codemodder.providers.sarif.semgrep.SemgrepScan; | ||
import java.util.Optional; | ||
import javax.inject.Inject; | ||
|
||
@Codemod( | ||
id = "pixee:java/verbose-request-mapping", | ||
reviewGuidance = ReviewGuidance.MERGE_WITHOUT_REVIEW) | ||
public final class VerboseRequestMappingCodemod | ||
extends SarifPluginJavaParserChanger<NormalAnnotationExpr> { | ||
|
||
@Inject | ||
public VerboseRequestMappingCodemod( | ||
@SemgrepScan(ruleId = "verbose-request-mapping") final RuleSarif sarif) { | ||
super(sarif, NormalAnnotationExpr.class); | ||
} | ||
|
||
@Override | ||
public boolean onResultFound( | ||
final CodemodInvocationContext context, | ||
final CompilationUnit cu, | ||
final NormalAnnotationExpr annotationExpr, | ||
final Result result) { | ||
|
||
// Find the http method if it exists | ||
Optional<MemberValuePair> method = | ||
annotationExpr.getPairs().stream() | ||
.filter(pair -> pair.getNameAsString().equals("method")) | ||
.findFirst(); | ||
if (method.isPresent()) { | ||
MemberValuePair methodAttribute = method.get(); | ||
// Store method and remove the "method" attribute | ||
String httpMethod = methodAttribute.getValue().toString(); | ||
Optional<String> newType = getType(httpMethod); | ||
if (newType.isPresent()) { | ||
annotationExpr.getPairs().remove(methodAttribute); | ||
annotationExpr.setName(newType.get()); | ||
addImportIfMissing(cu, "org.springframework.web.bind.annotation." + newType.get()); | ||
return true; | ||
} | ||
} | ||
return false; | ||
} | ||
|
||
public static Optional<String> getType(final String httpMethod) { | ||
String newType = | ||
switch (httpMethod) { | ||
case "RequestMethod.GET", "GET" -> "GetMapping"; | ||
case "RequestMethod.PUT", "PUT" -> "PutMapping"; | ||
case "RequestMethod.DELETE", "DELETE" -> "DeleteMapping"; | ||
case "RequestMethod.POST", "POST" -> "PostMapping"; | ||
case "RequestMethod.PATCH", "PATCH" -> "PatchMapping"; | ||
default -> null; | ||
}; | ||
return Optional.ofNullable(newType); | ||
} | ||
} |
19 changes: 19 additions & 0 deletions
19
...in/resources/io/codemodder/codemods/VerboseRequestMappingCodemod/description.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
This change simplifies Spring Framework annotations by making use of shortened annotations when applicable. | ||
Code that is easy to read is easy to review, reason about, and detect bugs in. | ||
|
||
Making use of shortcut annotations accomplishes this by removing *wordy for no reason* elements. | ||
|
||
|
||
Version 4.3 of Spring Framework introduced method-level variants for `@RequestMapping`. | ||
- `@GetMapping` | ||
- `@PutMapping` | ||
- `@PostMapping` | ||
- `@DeleteMapping` | ||
- `@PatchMapping` | ||
|
||
```diff | ||
- @RequestMapping(value = "/example", method = RequestMethod.GET) | ||
... | ||
+ @GetMapping(value = "/example") | ||
``` | ||
|
8 changes: 8 additions & 0 deletions
8
...demods/src/main/resources/io/codemodder/codemods/VerboseRequestMappingCodemod/report.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
{ | ||
"summary": "Replaced @RequestMapping annotation with shortcut annotation for requested HTTP Method", | ||
"change": "Replaced @RequestMapping annotation with shortcut annotation for requested HTTP Method", | ||
"references": [ | ||
"https://docs.spring.io/spring-framework/reference/web/webmvc/mvc-controller/ann-requestmapping.html", | ||
"https://dzone.com/articles/using-the-spring-requestmapping-annotation" | ||
] | ||
} |
11 changes: 11 additions & 0 deletions
11
core-codemods/src/main/resources/io/codemodder/codemods/verbose-request-mapping.yaml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
rules: | ||
- id: verbose-request-mapping | ||
patterns: | ||
- pattern-either: | ||
- pattern: | | ||
@RequestMapping(method = $REQUEST_METHOD, ...) | ||
- pattern: | | ||
@RequestMapping(method = $VALUE, ...) | ||
message: Semgrep found a match. | ||
languages: [java] | ||
severity: WARNING |
10 changes: 10 additions & 0 deletions
10
core-codemods/src/test/java/io/codemodder/codemods/VerboseRequestMappingCodemodTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package io.codemodder.codemods; | ||
|
||
import io.codemodder.testutils.CodemodTestMixin; | ||
import io.codemodder.testutils.Metadata; | ||
|
||
@Metadata( | ||
codemodType = VerboseRequestMappingCodemod.class, | ||
testResourceDir = "verbose-request-mapping", | ||
dependencies = {}) | ||
final class VerboseRequestMappingCodemodTest implements CodemodTestMixin {} |
78 changes: 78 additions & 0 deletions
78
core-codemods/src/test/resources/verbose-request-mapping/Test.java.after
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
import org.springframework.web.bind.annotation.DeleteMapping; | ||
import org.springframework.web.bind.annotation.GetMapping; | ||
import org.springframework.web.bind.annotation.PostMapping; | ||
import org.springframework.web.bind.annotation.PutMapping; | ||
import org.springframework.web.bind.annotation.RequestMapping; | ||
import org.springframework.web.bind.annotation.RequestMethod; | ||
import org.springframework.web.bind.annotation.RestController; | ||
|
||
public class Test { | ||
|
||
@RequestMapping("/example1") | ||
public String case1() { | ||
return "Case 1"; | ||
} | ||
|
||
@GetMapping(value = "/example2") | ||
public String case2() { | ||
return "Case 2"; | ||
} | ||
|
||
@GetMapping(value = "/example3") | ||
public String case3() { | ||
return "Case 3"; | ||
} | ||
|
||
@RequestMapping(value = "/example4") | ||
public String case4() { | ||
return "Case 4"; | ||
} | ||
|
||
@NonsenseMapping(value = "/example5") | ||
public String case5() { return "Case 5"; } | ||
|
||
@NonsenseMapping(value = "/example6", method = RequestMethod.NONSENSE) | ||
public String case6() { return "Case 6"; } | ||
|
||
} | ||
|
||
@Controller | ||
@RequestMapping("/boys") | ||
public class DemoController { | ||
|
||
@ResponseBody | ||
@RequestMapping("/hello") | ||
public String helloWorld() { | ||
return "Hello World!"; | ||
} | ||
|
||
@ResponseBody | ||
@RequestMapping("/example") | ||
public String welcomeGfgMessage() { | ||
return "Welcome"; | ||
} | ||
|
||
@ResponseBody | ||
@GetMapping(value = "/greet") | ||
public String greet() { | ||
return "Greetings!"; | ||
} | ||
|
||
@ResponseBody | ||
@PutMapping(value = "/update") | ||
public String updateData() { | ||
return "Data Updated!"; | ||
} | ||
|
||
@ResponseBody | ||
@DeleteMapping(value = "/delete") | ||
public String deleteData() { | ||
return "Data Deleted!"; | ||
} | ||
|
||
@ResponseBody | ||
@PostMapping(value = "/create") | ||
public String createData() { | ||
return "Data Created!"; | ||
} | ||
} |
74 changes: 74 additions & 0 deletions
74
core-codemods/src/test/resources/verbose-request-mapping/Test.java.before
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
import org.springframework.web.bind.annotation.RequestMapping; | ||
import org.springframework.web.bind.annotation.RequestMethod; | ||
import org.springframework.web.bind.annotation.RestController; | ||
|
||
public class Test { | ||
|
||
@RequestMapping("/example1") | ||
public String case1() { | ||
return "Case 1"; | ||
} | ||
|
||
@RequestMapping(method = RequestMethod.GET, value = "/example2") | ||
public String case2() { | ||
return "Case 2"; | ||
} | ||
|
||
@RequestMapping(value = "/example3", method = GET) | ||
public String case3() { | ||
return "Case 3"; | ||
} | ||
|
||
@RequestMapping(value = "/example4") | ||
public String case4() { | ||
return "Case 4"; | ||
} | ||
|
||
@NonsenseMapping(value = "/example5") | ||
public String case5() { return "Case 5"; } | ||
|
||
@NonsenseMapping(value = "/example6", method = RequestMethod.NONSENSE) | ||
public String case6() { return "Case 6"; } | ||
|
||
} | ||
|
||
@Controller | ||
@RequestMapping("/boys") | ||
public class DemoController { | ||
|
||
@ResponseBody | ||
@RequestMapping("/hello") | ||
public String helloWorld() { | ||
return "Hello World!"; | ||
} | ||
|
||
@ResponseBody | ||
@RequestMapping("/example") | ||
public String welcomeGfgMessage() { | ||
return "Welcome"; | ||
} | ||
|
||
@ResponseBody | ||
@RequestMapping(value = "/greet", method = RequestMethod.GET) | ||
public String greet() { | ||
return "Greetings!"; | ||
} | ||
|
||
@ResponseBody | ||
@RequestMapping(value = "/update", method = RequestMethod.PUT) | ||
public String updateData() { | ||
return "Data Updated!"; | ||
} | ||
|
||
@ResponseBody | ||
@RequestMapping(value = "/delete", method = RequestMethod.DELETE) | ||
public String deleteData() { | ||
return "Data Deleted!"; | ||
} | ||
|
||
@ResponseBody | ||
@RequestMapping(value = "/create", method = RequestMethod.POST) | ||
public String createData() { | ||
return "Data Created!"; | ||
} | ||
} |