diff --git a/rules/S6814/java/metadata.json b/rules/S6814/java/metadata.json new file mode 100644 index 00000000000..e2f09b6a6db --- /dev/null +++ b/rules/S6814/java/metadata.json @@ -0,0 +1,23 @@ +{ + "title": "Optional REST parameters should have an object type", + "type": "CODE_SMELL", + "status": "ready", + "remediation": { + "func": "Constant\/Issue", + "constantCost": "5min" + }, + "tags": [ + ], + "defaultSeverity": "Major", + "ruleSpecification": "RSPEC-6814", + "sqKey": "S6814", + "scope": "All", + "defaultQualityProfiles": ["Sonar way"], + "quickfix": "unknown", + "code": { + "impacts": { + "RELIABILITY": "HIGH" + }, + "attribute": "CONVENTIONAL" + } +} diff --git a/rules/S6814/java/rule.adoc b/rules/S6814/java/rule.adoc new file mode 100644 index 00000000000..694e48d96cc --- /dev/null +++ b/rules/S6814/java/rule.adoc @@ -0,0 +1,68 @@ +== Why is this an issue? + +Spring provides two options to mark a REST parameter as optional: + +1. Use `required = false` in the `@PathVariable` or `@RequestParam` annotation of the respective method parameter or +2. Use type `java.util.Optional` for the method parameter + +When using 1., the absence of the parameter, when the REST function is called, is encoded by `null`, which can only be used for object types. +If `required = false` is used for a parameter with a primitive and the REST function is called without the parameter, a runtime exception occurs because the Spring data mapper cannot map the `null` value to the parameter. + +== How to fix it + +Replace primitive types, such as `boolean`, `char`, `int`, with the corresponding wrapper type, such as `Boolean`, `Character`, `Integer`. + +Alternatively, you might choose to remove `required = false` from the annotation and use an `Optional` type for the parameter, such as `Optional` or `Optional`, which automatically makes the REST parameter optional. +This is the preferred approach because it enforces the proper handling of `null` in the method implementation. + +=== Code examples + +==== Noncompliant code example + +[source,java,diff-id=1,diff-type=noncompliant] +---- +@RequestMapping(value = {"/article", "/article/{id}"}) +public Article getArticle(@PathVariable(required = false) int articleId) { // Noncompliant, null cannot be mapped to int + //... +} +---- + +==== Compliant solution + +[source,java,diff-id=1,diff-type=compliant] +---- +@RequestMapping(value = {"/article", "/article/{id}"}) +public Article getArticle(@PathVariable(required = false) Integer articleId) { // Compliant + //... +} +---- + +==== Noncompliant code example + +[source,java,diff-id=2,diff-type=noncompliant] +---- +@RequestMapping(value = {"/article", "/article/{id}"}) +public Article getArticle(@PathVariable(required = false) int articleId) { // Noncompliant, null cannot be mapped to int + //... +} +---- + +==== Compliant solution + +[source,java,diff-id=2,diff-type=compliant] +---- +@RequestMapping(value = {"/article", "/article/{id}"}) +public Article getArticle(@PathVariable Optional articleId) { // Compliant and preferred approach + //... +} +---- + +== Resources + +=== Documentation + +- https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/bind/annotation/PathVariable.html[Spring Framework API - Annotation Interface PathVariable] + +=== Articles & blog posts + +- https://www.baeldung.com/spring-optional-path-variables[Baeldung - Spring Optional Path Variables] diff --git a/rules/S6814/metadata.json b/rules/S6814/metadata.json new file mode 100644 index 00000000000..2c63c085104 --- /dev/null +++ b/rules/S6814/metadata.json @@ -0,0 +1,2 @@ +{ +}