From 3d90b19ab512fb6238ff740a4252ab7c0ac82f7e Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Mon, 11 Sep 2023 17:11:08 +0300 Subject: [PATCH] Updated @RequestParam#required handling The previous way was misleading and led to incorrect results when non-String types were being used. The reason we can don't support required=true is that JAX-RS does not have the concept of a required parameter so to fix this would need to introduce something specific to RESTEasy Reactive --- .../SpringWebResteasyReactiveProcessor.java | 12 +++-- .../spring/web/test/RequiredFalseTest.java | 50 +++++++++++++++++++ 2 files changed, 57 insertions(+), 5 deletions(-) create mode 100644 extensions/spring-web/resteasy-reactive/tests/src/test/java/io/quarkus/spring/web/test/RequiredFalseTest.java diff --git a/extensions/spring-web/resteasy-reactive/deployment/src/main/java/io/quarkus/spring/web/deployment/SpringWebResteasyReactiveProcessor.java b/extensions/spring-web/resteasy-reactive/deployment/src/main/java/io/quarkus/spring/web/deployment/SpringWebResteasyReactiveProcessor.java index e33a2ab086355..3c01c23dcabe8 100644 --- a/extensions/spring-web/resteasy-reactive/deployment/src/main/java/io/quarkus/spring/web/deployment/SpringWebResteasyReactiveProcessor.java +++ b/extensions/spring-web/resteasy-reactive/deployment/src/main/java/io/quarkus/spring/web/deployment/SpringWebResteasyReactiveProcessor.java @@ -289,19 +289,21 @@ public void transform(TransformationContext transformationContext) { } transform.add(create(jaxRsAnnotation, annotation.target(), annotationValues)); - boolean required = true; // the default value - String defaultValueStr = DEFAULT_NONE; // default value of @RequestMapping#defaultValue + String defaultValueStr = null; AnnotationValue defaultValue = annotation.value("defaultValue"); if (defaultValue != null) { defaultValueStr = defaultValue.asString(); - required = false; // implicitly set according to the javadoc of @RequestMapping#defaultValue } else { AnnotationValue requiredValue = annotation.value("required"); if (requiredValue != null) { - required = requiredValue.asBoolean(); + if (requiredValue.asBoolean()) { + throw new IllegalArgumentException( + "Using required @RequestMapping is not supported. Offending method is '" + + methodInfo.declaringClass().name() + "#" + methodInfo.name() + "'"); + } } } - if (!required) { + if (defaultValueStr != null) { transform.add(create(DEFAULT_VALUE, annotation.target(), Collections .singletonList(AnnotationValue.createStringValue("value", defaultValueStr)))); diff --git a/extensions/spring-web/resteasy-reactive/tests/src/test/java/io/quarkus/spring/web/test/RequiredFalseTest.java b/extensions/spring-web/resteasy-reactive/tests/src/test/java/io/quarkus/spring/web/test/RequiredFalseTest.java new file mode 100644 index 0000000000000..f7cae709aa99e --- /dev/null +++ b/extensions/spring-web/resteasy-reactive/tests/src/test/java/io/quarkus/spring/web/test/RequiredFalseTest.java @@ -0,0 +1,50 @@ +package io.quarkus.spring.web.test; + +import static io.restassured.RestAssured.when; +import static org.hamcrest.Matchers.is; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import io.quarkus.test.QuarkusUnitTest; + +public class RequiredFalseTest { + + @RegisterExtension + static QuarkusUnitTest runner = new QuarkusUnitTest() + .withApplicationRoot((jar) -> jar + .addClasses(Controller.class)); + + @Test + public void test() { + when().get("/endpoint/boxed") + .then() + .statusCode(200) + .body(is("")); + + when().get("/endpoint/primitive") + .then() + .statusCode(200) + .body(is("0")); + } + + @RestController + @RequestMapping("/endpoint") + public static class Controller { + + @GetMapping("/boxed") + public ResponseEntity boxed(@RequestParam(value = "id", required = false) Long id) { + return ResponseEntity.ok(id); + } + + @GetMapping("/primitive") + public ResponseEntity primitive(@RequestParam(value = "id", required = false) long id) { + return ResponseEntity.ok(id); + } + } +}