diff --git a/core/src/main/java/io/smallrye/openapi/runtime/scanner/FilteredIndexView.java b/core/src/main/java/io/smallrye/openapi/runtime/scanner/FilteredIndexView.java index 95253e7d1..55800f57d 100644 --- a/core/src/main/java/io/smallrye/openapi/runtime/scanner/FilteredIndexView.java +++ b/core/src/main/java/io/smallrye/openapi/runtime/scanner/FilteredIndexView.java @@ -48,7 +48,8 @@ public FilteredIndexView(IndexView delegate, OpenApiConfig config) { * Returns true if the class name should be included in the index (is either included or * not excluded). * - * @param className + * @param className the name of the class + * @return true if the inclusion/exclusion configuration allows scanning of the class name */ public boolean accepts(DotName className) { final boolean accept; diff --git a/extension-jaxrs/src/main/java/io/smallrye/openapi/jaxrs/ParameterProcessor.java b/extension-jaxrs/src/main/java/io/smallrye/openapi/jaxrs/ParameterProcessor.java index 81a6c35d1..dba40c523 100644 --- a/extension-jaxrs/src/main/java/io/smallrye/openapi/jaxrs/ParameterProcessor.java +++ b/extension-jaxrs/src/main/java/io/smallrye/openapi/jaxrs/ParameterProcessor.java @@ -1219,15 +1219,17 @@ ParameterContext getParameterContext(ParameterContextKey key, AnnotationTarget t } boolean haveSameAnnotatedTarget(ParameterContext context, AnnotationTarget target, String name) { - boolean nameMatches = Objects.equals(context.name, name); + /* + * Consider names to match if one is unspecified or they are equal. + */ + boolean nameMatches = (context.name == null || name == null || Objects.equals(context.name, name)); if (target.equals(context.target)) { /* - * This logic formerly also required that the parameter names matched - * (nameMatches == true) or that the kind of the target was not a - * method. + * The name must match for annotations on a method because it is + * ambiguous which parameters is being referenced. */ - return true; + return nameMatches || target.kind() != Kind.METHOD; } if (nameMatches && target.kind() == Kind.METHOD && context.target.kind() == Kind.METHOD_PARAMETER) { diff --git a/extension-jaxrs/src/test/java/io/smallrye/openapi/runtime/scanner/ResourceParameterTests.java b/extension-jaxrs/src/test/java/io/smallrye/openapi/runtime/scanner/ResourceParameterTests.java index 518e01f08..ab241260a 100644 --- a/extension-jaxrs/src/test/java/io/smallrye/openapi/runtime/scanner/ResourceParameterTests.java +++ b/extension-jaxrs/src/test/java/io/smallrye/openapi/runtime/scanner/ResourceParameterTests.java @@ -6,9 +6,13 @@ import java.time.OffsetTime; import java.time.ZoneId; import java.time.ZoneOffset; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Set; +import javax.enterprise.context.RequestScoped; import javax.ws.rs.BeanParam; import javax.ws.rs.Consumes; import javax.ws.rs.CookieParam; @@ -25,9 +29,13 @@ import javax.ws.rs.core.Response; import org.eclipse.microprofile.openapi.annotations.Operation; +import org.eclipse.microprofile.openapi.annotations.enums.ParameterIn; import org.eclipse.microprofile.openapi.annotations.enums.SchemaType; +import org.eclipse.microprofile.openapi.annotations.headers.Header; import org.eclipse.microprofile.openapi.annotations.media.Content; import org.eclipse.microprofile.openapi.annotations.media.Schema; +import org.eclipse.microprofile.openapi.annotations.parameters.Parameter; +import org.eclipse.microprofile.openapi.annotations.parameters.Parameters; import org.eclipse.microprofile.openapi.annotations.parameters.RequestBody; import org.eclipse.microprofile.openapi.annotations.responses.APIResponse; import org.eclipse.microprofile.openapi.annotations.responses.APIResponses; @@ -477,4 +485,78 @@ public Response getWithBeanParams(@BeanParam BeanParamImpl params) { return null; } } + + /*************************************************************************/ + /* + * Test case derived from original example in SmallRye OpenAPI issue #330. + * + * https://github.com/smallrye/smallrye-open-api/issues/330 + * + */ + + @Test + public void testMethodTargetParametersWithoutJAXRS() throws IOException, JSONException { + Index i = indexOf(MethodTargetParametersResource.class, + MethodTargetParametersResource.PagedResponse.class); + OpenApiAnnotationScanner scanner = new OpenApiAnnotationScanner(emptyConfig(), i); + OpenAPI result = scanner.scan(); + printToConsole(result); + assertJsonEquals("params.method-target-nojaxrs.json", result); + } + + @Path("/policies") + @Produces("application/json") + @Consumes("application/json") + @RequestScoped + static class MethodTargetParametersResource { + static class PagedResponse { + public Map meta = new HashMap<>(1); + public Map links = new HashMap<>(3); + public List data = new ArrayList<>(); + } + + @Operation(summary = "Return all policies for a given account") + @GET + @Path("/") + @Parameters({ + @Parameter(name = "offset", in = ParameterIn.QUERY, description = "Page number, starts 0, if not specified uses 0.", schema = @Schema(type = SchemaType.INTEGER)), + @Parameter(name = "limit", in = ParameterIn.QUERY, description = "Number of items per page, if not specified uses 10. " + + "NO_LIMIT can be used to specify an unlimited page, when specified it ignores the offset", schema = @Schema(type = SchemaType.INTEGER)), + @Parameter(name = "sortColumn", in = ParameterIn.QUERY, description = "Column to sort the results by", schema = @Schema(type = SchemaType.STRING, enumeration = { + "name", + "description", + "is_enabled", + "mtime" + })), + @Parameter(name = "sortDirection", in = ParameterIn.QUERY, description = "Sort direction used", schema = @Schema(type = SchemaType.STRING, enumeration = { + "asc", + "desc" + })), + @Parameter(name = "filter[name]", in = ParameterIn.QUERY, description = "Filtering policies by the name depending on the Filter operator used.", schema = @Schema(type = SchemaType.STRING)), + @Parameter(name = "filter:op[name]", in = ParameterIn.QUERY, description = "Operations used with the filter", schema = @Schema(type = SchemaType.STRING, enumeration = { + "equal", + "like", + "ilike", + "not_equal" + }, defaultValue = "equal")), + @Parameter(name = "filter[description]", in = ParameterIn.QUERY, description = "Filtering policies by the description depending on the Filter operator used.", schema = @Schema(type = SchemaType.STRING)), + @Parameter(name = "filter:op[description]", in = ParameterIn.QUERY, description = "Operations used with the filter", schema = @Schema(type = SchemaType.STRING, enumeration = { + "equal", + "like", + "ilike", + "not_equal" + }, defaultValue = "equal")), + @Parameter(name = "filter[is_enabled]", in = ParameterIn.QUERY, description = "Filtering policies by the is_enabled field." + + + "Defaults to true if no operand is given.", schema = @Schema(type = SchemaType.STRING, defaultValue = "true", enumeration = { + "true", "false" })), + }) + @APIResponse(responseCode = "400", description = "Bad parameter for sorting was passed") + @APIResponse(responseCode = "404", description = "No policies found for customer") + @APIResponse(responseCode = "403", description = "Individual permissions missing to complete action") + @APIResponse(responseCode = "200", description = "Policies found", content = @Content(schema = @Schema(implementation = PagedResponse.class)), headers = @Header(name = "TotalCount", description = "Total number of items found", schema = @Schema(type = SchemaType.INTEGER))) + public Response getPoliciesForCustomer() { + return null; + } + } } diff --git a/extension-jaxrs/src/test/resources/io/smallrye/openapi/runtime/scanner/params.method-target-nojaxrs.json b/extension-jaxrs/src/test/resources/io/smallrye/openapi/runtime/scanner/params.method-target-nojaxrs.json new file mode 100644 index 000000000..394d129ef --- /dev/null +++ b/extension-jaxrs/src/test/resources/io/smallrye/openapi/runtime/scanner/params.method-target-nojaxrs.json @@ -0,0 +1,171 @@ +{ + "openapi": "3.0.1", + "paths": { + "/policies": { + "get": { + "summary": "Return all policies for a given account", + "parameters": [ + { + "name": "filter:op[description]", + "in": "query", + "description": "Operations used with the filter", + "schema": { + "default": "equal", + "enum": [ + "equal", + "like", + "ilike", + "not_equal" + ], + "type": "string" + } + }, + { + "name": "filter:op[name]", + "in": "query", + "description": "Operations used with the filter", + "schema": { + "default": "equal", + "enum": [ + "equal", + "like", + "ilike", + "not_equal" + ], + "type": "string" + } + }, + { + "name": "filter[description]", + "in": "query", + "description": "Filtering policies by the description depending on the Filter operator used.", + "schema": { + "type": "string" + } + }, + { + "name": "filter[is_enabled]", + "in": "query", + "description": "Filtering policies by the is_enabled field.Defaults to true if no operand is given.", + "schema": { + "default": "true", + "enum": [ + "true", + "false" + ], + "type": "string" + } + }, + { + "name": "filter[name]", + "in": "query", + "description": "Filtering policies by the name depending on the Filter operator used.", + "schema": { + "type": "string" + } + }, + { + "name": "limit", + "in": "query", + "description": "Number of items per page, if not specified uses 10. NO_LIMIT can be used to specify an unlimited page, when specified it ignores the offset", + "schema": { + "type": "integer" + } + }, + { + "name": "offset", + "in": "query", + "description": "Page number, starts 0, if not specified uses 0.", + "schema": { + "type": "integer" + } + }, + { + "name": "sortColumn", + "in": "query", + "description": "Column to sort the results by", + "schema": { + "enum": [ + "name", + "description", + "is_enabled", + "mtime" + ], + "type": "string" + } + }, + { + "name": "sortDirection", + "in": "query", + "description": "Sort direction used", + "schema": { + "enum": [ + "asc", + "desc" + ], + "type": "string" + } + } + ], + "responses": { + "400": { + "description": "Bad parameter for sorting was passed" + }, + "404": { + "description": "No policies found for customer" + }, + "403": { + "description": "Individual permissions missing to complete action" + }, + "200": { + "description": "Policies found", + "headers": { + "TotalCount": { + "description": "Total number of items found", + "style": "simple", + "schema": { + "type": "integer" + } + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PagedResponse" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "PagedResponse": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "type": "object" + } + }, + "links": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "meta": { + "type": "object", + "additionalProperties": { + "format": "int64", + "type": "integer" + } + } + } + } + } + } +}