diff --git a/extension-spring/pom.xml b/extension-spring/pom.xml index 13f40bb8d..ce959a27f 100644 --- a/extension-spring/pom.xml +++ b/extension-spring/pom.xml @@ -63,6 +63,17 @@ spring-webmvc test + + javax.servlet + javax.servlet-api + 3.1.0 + test + + + jakarta.servlet + jakarta.servlet-api + test + diff --git a/extension-spring/src/main/java/io/smallrye/openapi/spring/SpringAnnotationScanner.java b/extension-spring/src/main/java/io/smallrye/openapi/spring/SpringAnnotationScanner.java index a83cf8e57..1a46a864e 100644 --- a/extension-spring/src/main/java/io/smallrye/openapi/spring/SpringAnnotationScanner.java +++ b/extension-spring/src/main/java/io/smallrye/openapi/spring/SpringAnnotationScanner.java @@ -93,6 +93,11 @@ public boolean isMultipartInput(Type inputType) { return SpringConstants.MULTIPART_INPUTS.contains(inputType.name()); } + @Override + public boolean isFrameworkContextType(Type type) { + return SpringConstants.CONTEXTS.contains(type.name()); + } + @Override public boolean containsScannerAnnotations(List instances, List extensions) { diff --git a/extension-spring/src/main/java/io/smallrye/openapi/spring/SpringConstants.java b/extension-spring/src/main/java/io/smallrye/openapi/spring/SpringConstants.java index df47e387a..51d58d14f 100644 --- a/extension-spring/src/main/java/io/smallrye/openapi/spring/SpringConstants.java +++ b/extension-spring/src/main/java/io/smallrye/openapi/spring/SpringConstants.java @@ -4,6 +4,8 @@ import java.util.Collections; import java.util.HashSet; import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; import org.jboss.jandex.DotName; @@ -34,6 +36,14 @@ public class SpringConstants { static final DotName HEADER_PARAM = DotName.createSimple("org.springframework.web.bind.annotation.RequestHeader"); static final DotName MATRIX_PARAM = DotName.createSimple("org.springframework.web.bind.annotation.MatrixVariable"); + static final Set CONTEXTS = Stream.of("javax", "jakarta") + .map(prefix -> DotName.createComponentized(null, prefix)) + .map(prefix -> DotName.createComponentized(prefix, "servlet")) + .map(prefix -> DotName.createComponentized(prefix, "http")) + .flatMap(prefix -> Stream.of("HttpServletRequest", "HttpServletResponse", "HttpSession") + .map(simpleName -> DotName.createComponentized(prefix, simpleName))) + .collect(Collectors.toSet()); + public static final Set MULTIPART_OUTPUTS = Collections .unmodifiableSet(new HashSet<>(Arrays.asList(MUTIPART_FILE))); diff --git a/extension-spring/src/test/java/io/smallrye/openapi/runtime/scanner/SpringAnnotationScannerTest.java b/extension-spring/src/test/java/io/smallrye/openapi/runtime/scanner/SpringAnnotationScannerTest.java index 82a5dc89a..e65c24231 100644 --- a/extension-spring/src/test/java/io/smallrye/openapi/runtime/scanner/SpringAnnotationScannerTest.java +++ b/extension-spring/src/test/java/io/smallrye/openapi/runtime/scanner/SpringAnnotationScannerTest.java @@ -17,6 +17,8 @@ import test.io.smallrye.openapi.runtime.scanner.resources.GreetingPostControllerAlt; import test.io.smallrye.openapi.runtime.scanner.resources.GreetingPutController; import test.io.smallrye.openapi.runtime.scanner.resources.GreetingPutControllerAlt; +import test.io.smallrye.openapi.runtime.scanner.resources.javax.GreetingPostControllerWithServletContext; +import test.io.smallrye.openapi.runtime.scanner.resources.javax.GreetingPutControllerWithServletContext; /** * Basic Spring annotation scanning @@ -114,6 +116,44 @@ void testBasicPostSpringDefinitionScanningAlt() throws IOException, JSONExceptio assertJsonEquals("resource.testBasicSpringPostDefinitionScanning.json", result); } + /** + * This test a basic, no OpenApi annotations, hello world service + * + * @throws IOException + * @throws JSONException + */ + @Test + void testBasicPostSpringDefinitionScanningWithServletContextJakarta() throws IOException, JSONException { + Index i = indexOf( + test.io.smallrye.openapi.runtime.scanner.resources.jakarta.GreetingPostControllerWithServletContext.class, + Greeting.class); + OpenApiAnnotationScanner scanner = new OpenApiAnnotationScanner(emptyConfig(), i); + + OpenAPI result = scanner.scan(); + + printToConsole(result); + assertJsonEquals("resource.testBasicSpringPostDefinitionScanning.json", result); + } + + /** + * This test a basic, no OpenApi annotations, hello world service + * + * @throws IOException + * @throws JSONException + */ + @Test + void testBasicPostSpringDefinitionScanningWithServletContextJavax() throws IOException, JSONException { + Index i = indexOf( + test.io.smallrye.openapi.runtime.scanner.resources.javax.GreetingPostControllerWithServletContext.class, + Greeting.class); + OpenApiAnnotationScanner scanner = new OpenApiAnnotationScanner(emptyConfig(), i); + + OpenAPI result = scanner.scan(); + + printToConsole(result); + assertJsonEquals("resource.testBasicSpringPostDefinitionScanning.json", result); + } + /** * This test a basic, no OpenApi annotations, hello world service * @@ -148,6 +188,44 @@ void testBasicPutSpringDefinitionScanningAlt() throws IOException, JSONException assertJsonEquals("resource.testBasicSpringPutDefinitionScanning.json", result); } + /** + * This test a basic, no OpenApi annotations, hello world service + * + * @throws IOException + * @throws JSONException + */ + @Test + void testBasicPutSpringDefinitionScanningWithServletContextJakarta() throws IOException, JSONException { + Index i = indexOf( + test.io.smallrye.openapi.runtime.scanner.resources.jakarta.GreetingPutControllerWithServletContext.class, + Greeting.class); + OpenApiAnnotationScanner scanner = new OpenApiAnnotationScanner(emptyConfig(), i); + + OpenAPI result = scanner.scan(); + + printToConsole(result); + assertJsonEquals("resource.testBasicSpringPutDefinitionScanning.json", result); + } + + /** + * This test a basic, no OpenApi annotations, hello world service + * + * @throws IOException + * @throws JSONException + */ + @Test + void testBasicPutSpringDefinitionScanningWithServletContextJavax() throws IOException, JSONException { + Index i = indexOf( + test.io.smallrye.openapi.runtime.scanner.resources.javax.GreetingPutControllerWithServletContext.class, + Greeting.class); + OpenApiAnnotationScanner scanner = new OpenApiAnnotationScanner(emptyConfig(), i); + + OpenAPI result = scanner.scan(); + + printToConsole(result); + assertJsonEquals("resource.testBasicSpringPutDefinitionScanning.json", result); + } + /** * This test a basic, no OpenApi annotations, hello world service * diff --git a/extension-spring/src/test/java/test/io/smallrye/openapi/runtime/scanner/resources/jakarta/GreetingPostControllerWithServletContext.java b/extension-spring/src/test/java/test/io/smallrye/openapi/runtime/scanner/resources/jakarta/GreetingPostControllerWithServletContext.java new file mode 100644 index 000000000..93e619af9 --- /dev/null +++ b/extension-spring/src/test/java/test/io/smallrye/openapi/runtime/scanner/resources/jakarta/GreetingPostControllerWithServletContext.java @@ -0,0 +1,49 @@ +package test.io.smallrye.openapi.runtime.scanner.resources.jakarta; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpSession; + +import org.eclipse.microprofile.openapi.annotations.media.Content; +import org.eclipse.microprofile.openapi.annotations.media.Schema; +import org.eclipse.microprofile.openapi.annotations.responses.APIResponse; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import test.io.smallrye.openapi.runtime.scanner.entities.Greeting; + +/** + * Spring. + * Some basic test, comparing with what we get in the JAX-RS version. + * See the GreetingPostResource in the JAX-RS test + * + * @author Phillip Kruger (phillip.kruger@redhat.com) + */ +@RestController +@RequestMapping(value = "/greeting", produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE) +public class GreetingPostControllerWithServletContext { + + // 1) Basic path var test + @PostMapping("/greet") + public Greeting greet(HttpServletRequest request, HttpServletResponse response, @RequestBody Greeting greeting) { + return greeting; + } + + // 2) ResponseEntity without a type specified + @PostMapping("/greetWithResponse") + @APIResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(ref = "#/components/schemas/Greeting"))) + public ResponseEntity greetWithResponse(@RequestBody Greeting greeting, HttpServletRequest request, + HttpServletResponse response) { + return ResponseEntity.ok(greeting); + } + + // 3) ResponseEntity with a type specified (No JaxRS comparison) + @PostMapping("/greetWithResponseTyped") + public ResponseEntity greetWithResponseTyped(HttpSession session, @RequestBody Greeting greeting) { + return ResponseEntity.ok(greeting); + } +} diff --git a/extension-spring/src/test/java/test/io/smallrye/openapi/runtime/scanner/resources/jakarta/GreetingPutControllerWithServletContext.java b/extension-spring/src/test/java/test/io/smallrye/openapi/runtime/scanner/resources/jakarta/GreetingPutControllerWithServletContext.java new file mode 100644 index 000000000..203f3840f --- /dev/null +++ b/extension-spring/src/test/java/test/io/smallrye/openapi/runtime/scanner/resources/jakarta/GreetingPutControllerWithServletContext.java @@ -0,0 +1,52 @@ +package test.io.smallrye.openapi.runtime.scanner.resources.jakarta; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpSession; + +import org.eclipse.microprofile.openapi.annotations.media.Content; +import org.eclipse.microprofile.openapi.annotations.media.Schema; +import org.eclipse.microprofile.openapi.annotations.responses.APIResponse; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import test.io.smallrye.openapi.runtime.scanner.entities.Greeting; + +/** + * Spring. + * Some basic test, comparing with what we get in the JAX-RS version. + * See the GreetingPutResource in the JAX-RS test + * + * @author Phillip Kruger (phillip.kruger@redhat.com) + */ +@RestController +@RequestMapping(value = "/greeting", produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE) +public class GreetingPutControllerWithServletContext { + + // 1) Basic path var test + @PutMapping("/greet/{id}") + public Greeting greet(HttpServletRequest request, HttpServletResponse response, @RequestBody Greeting greeting, + @PathVariable(name = "id") String id) { + return greeting; + } + + // 2) ResponseEntity without a type specified + @PutMapping("/greetWithResponse/{id}") + @APIResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(ref = "#/components/schemas/Greeting"))) + public ResponseEntity greetWithResponse(@RequestBody Greeting greeting, @PathVariable(name = "id") String id, + HttpServletRequest request, HttpServletResponse response) { + return ResponseEntity.ok(greeting); + } + + // 3) ResponseEntity with a type specified (No JaxRS comparison) + @PutMapping("/greetWithResponseTyped/{id}") + public ResponseEntity greetWithResponseTyped(HttpSession session, @RequestBody Greeting greeting, + @PathVariable(name = "id") String id) { + return ResponseEntity.ok(greeting); + } +} diff --git a/extension-spring/src/test/java/test/io/smallrye/openapi/runtime/scanner/resources/javax/GreetingPostControllerWithServletContext.java b/extension-spring/src/test/java/test/io/smallrye/openapi/runtime/scanner/resources/javax/GreetingPostControllerWithServletContext.java new file mode 100644 index 000000000..75e245631 --- /dev/null +++ b/extension-spring/src/test/java/test/io/smallrye/openapi/runtime/scanner/resources/javax/GreetingPostControllerWithServletContext.java @@ -0,0 +1,49 @@ +package test.io.smallrye.openapi.runtime.scanner.resources.javax; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import org.eclipse.microprofile.openapi.annotations.media.Content; +import org.eclipse.microprofile.openapi.annotations.media.Schema; +import org.eclipse.microprofile.openapi.annotations.responses.APIResponse; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import test.io.smallrye.openapi.runtime.scanner.entities.Greeting; + +/** + * Spring. + * Some basic test, comparing with what we get in the JAX-RS version. + * See the GreetingPostResource in the JAX-RS test + * + * @author Phillip Kruger (phillip.kruger@redhat.com) + */ +@RestController +@RequestMapping(value = "/greeting", produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE) +public class GreetingPostControllerWithServletContext { + + // 1) Basic path var test + @PostMapping("/greet") + public Greeting greet(HttpServletRequest request, HttpServletResponse response, @RequestBody Greeting greeting) { + return greeting; + } + + // 2) ResponseEntity without a type specified + @PostMapping("/greetWithResponse") + @APIResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(ref = "#/components/schemas/Greeting"))) + public ResponseEntity greetWithResponse(@RequestBody Greeting greeting, HttpServletRequest request, + HttpServletResponse response) { + return ResponseEntity.ok(greeting); + } + + // 3) ResponseEntity with a type specified (No JaxRS comparison) + @PostMapping("/greetWithResponseTyped") + public ResponseEntity greetWithResponseTyped(HttpSession session, @RequestBody Greeting greeting) { + return ResponseEntity.ok(greeting); + } +} diff --git a/extension-spring/src/test/java/test/io/smallrye/openapi/runtime/scanner/resources/javax/GreetingPutControllerWithServletContext.java b/extension-spring/src/test/java/test/io/smallrye/openapi/runtime/scanner/resources/javax/GreetingPutControllerWithServletContext.java new file mode 100644 index 000000000..3a1af52ae --- /dev/null +++ b/extension-spring/src/test/java/test/io/smallrye/openapi/runtime/scanner/resources/javax/GreetingPutControllerWithServletContext.java @@ -0,0 +1,52 @@ +package test.io.smallrye.openapi.runtime.scanner.resources.javax; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import org.eclipse.microprofile.openapi.annotations.media.Content; +import org.eclipse.microprofile.openapi.annotations.media.Schema; +import org.eclipse.microprofile.openapi.annotations.responses.APIResponse; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import test.io.smallrye.openapi.runtime.scanner.entities.Greeting; + +/** + * Spring. + * Some basic test, comparing with what we get in the JAX-RS version. + * See the GreetingPutResource in the JAX-RS test + * + * @author Phillip Kruger (phillip.kruger@redhat.com) + */ +@RestController +@RequestMapping(value = "/greeting", produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE) +public class GreetingPutControllerWithServletContext { + + // 1) Basic path var test + @PutMapping("/greet/{id}") + public Greeting greet(HttpServletRequest request, HttpServletResponse response, @RequestBody Greeting greeting, + @PathVariable(name = "id") String id) { + return greeting; + } + + // 2) ResponseEntity without a type specified + @PutMapping("/greetWithResponse/{id}") + @APIResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(ref = "#/components/schemas/Greeting"))) + public ResponseEntity greetWithResponse(@RequestBody Greeting greeting, @PathVariable(name = "id") String id, + HttpServletRequest request, HttpServletResponse response) { + return ResponseEntity.ok(greeting); + } + + // 3) ResponseEntity with a type specified (No JaxRS comparison) + @PutMapping("/greetWithResponseTyped/{id}") + public ResponseEntity greetWithResponseTyped(HttpSession session, @RequestBody Greeting greeting, + @PathVariable(name = "id") String id) { + return ResponseEntity.ok(greeting); + } +}