From b2fb598517b2e44eebb1ad67ca3e1fb81d68a3a3 Mon Sep 17 00:00:00 2001 From: Elias Harb Date: Fri, 24 Jul 2026 17:42:11 +0200 Subject: [PATCH 1/3] feat(models): support OpenAPI 3.2 QUERY method in PathItem Add the `query` HTTP method introduced in OpenAPI 3.2 to PathItem: field, accessors and fluent builder, HttpMethod.QUERY enum constant, and wiring in readOperations, readOperationsMap, operation(), equals, hashCode and toString. Adds model tests plus a swagger-core serialization round-trip. Refs swagger-api/swagger-parser#2248 (https://github.com/swagger-api/swagger-parser/issues/2248) --- .../serialization/JsonSerializationTest.java | 28 +++++++ .../io/swagger/v3/oas/models/PathItem.java | 41 +++++++++- .../swagger/v3/oas/models/PathItemTest.java | 80 +++++++++++++++++++ 3 files changed, 148 insertions(+), 1 deletion(-) create mode 100644 modules/swagger-models/src/test/java/io/swagger/v3/oas/models/PathItemTest.java diff --git a/modules/swagger-core/src/test/java/io/swagger/v3/core/serialization/JsonSerializationTest.java b/modules/swagger-core/src/test/java/io/swagger/v3/core/serialization/JsonSerializationTest.java index 29163d0cca..0bed350252 100644 --- a/modules/swagger-core/src/test/java/io/swagger/v3/core/serialization/JsonSerializationTest.java +++ b/modules/swagger-core/src/test/java/io/swagger/v3/core/serialization/JsonSerializationTest.java @@ -23,6 +23,8 @@ import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; public class JsonSerializationTest { @@ -42,6 +44,32 @@ public void testSerializeASpecWithPathReferences() throws Exception { assertEquals(path, expectedPath); } + @Test + public void testSerializeQueryHttpMethod() throws Exception { + + Operation queryOperation = new Operation() + .operationId("searchPets") + .responses(new ApiResponses() + .addApiResponse("200", new ApiResponse().description("ok"))); + + OpenAPI openAPI = new OpenAPI() + .path("/pets", new PathItem().query(queryOperation)); + + String openAPIJson = Json.mapper().writeValueAsString(openAPI); + + // the OpenAPI 3.2 "query" method must be serialized ... + assertTrue(openAPIJson.contains("\"query\"")); + // ... and unset methods must not leak (NON_NULL inclusion) + assertFalse(openAPIJson.contains("\"get\"")); + + OpenAPI rebuilt = Json.mapper().readValue(openAPIJson, OpenAPI.class); + PathItem rebuiltPath = rebuilt.getPaths().get("/pets"); + + assertNotNull(rebuiltPath.getQuery()); + assertEquals(rebuiltPath.getQuery().getOperationId(), "searchPets"); + assertEquals(rebuiltPath, openAPI.getPaths().get("/pets")); + } + @Test public void testExtension() throws Exception { diff --git a/modules/swagger-models/src/main/java/io/swagger/v3/oas/models/PathItem.java b/modules/swagger-models/src/main/java/io/swagger/v3/oas/models/PathItem.java index 4b6acf8d80..048ce172f2 100644 --- a/modules/swagger-models/src/main/java/io/swagger/v3/oas/models/PathItem.java +++ b/modules/swagger-models/src/main/java/io/swagger/v3/oas/models/PathItem.java @@ -14,6 +14,7 @@ * * @see PathItem (OpenAPI 3.0 specification) * @see PathItem (OpenAPI 3.1 specification) + * @see PathItem (OpenAPI 3.2 specification) */ public class PathItem { @@ -27,6 +28,7 @@ public class PathItem { private Operation head = null; private Operation patch = null; private Operation trace = null; + private Operation query = null; private List servers = null; private List parameters = null; private String $ref = null; @@ -222,6 +224,28 @@ public PathItem trace(Operation trace) { return this; } + /** + * returns the query property from a PathItem instance. + * + *

The {@code query} HTTP method was introduced in OpenAPI 3.2. + * + * @return Operation query + * @since OpenAPI 3.2 + **/ + + public Operation getQuery() { + return query; + } + + public void setQuery(Operation query) { + this.query = query; + } + + public PathItem query(Operation query) { + this.query = query; + return this; + } + public List readOperations() { List allOperations = new ArrayList<>(); if (this.get != null) { @@ -248,6 +272,9 @@ public List readOperations() { if (this.trace != null) { allOperations.add(this.trace); } + if (this.query != null) { + allOperations.add(this.query); + } return allOperations; } @@ -278,6 +305,9 @@ public void operation(HttpMethod method, Operation operation) { case DELETE: this.delete = operation; break; + case QUERY: + this.query = operation; + break; default: } } @@ -290,7 +320,8 @@ public enum HttpMethod { DELETE, HEAD, OPTIONS, - TRACE + TRACE, + QUERY } public Map readOperationsMap() { @@ -320,6 +351,9 @@ public Map readOperationsMap() { if (this.trace != null) { result.put(HttpMethod.TRACE, this.trace); } + if (this.query != null) { + result.put(HttpMethod.QUERY, this.query); + } return result; } @@ -468,6 +502,9 @@ public boolean equals(Object o) { if (trace != null ? !trace.equals(pathItem.trace) : pathItem.trace != null) { return false; } + if (query != null ? !query.equals(pathItem.query) : pathItem.query != null) { + return false; + } if (servers != null ? !servers.equals(pathItem.servers) : pathItem.servers != null) { return false; } @@ -493,6 +530,7 @@ public int hashCode() { result = 31 * result + (head != null ? head.hashCode() : 0); result = 31 * result + (patch != null ? patch.hashCode() : 0); result = 31 * result + (trace != null ? trace.hashCode() : 0); + result = 31 * result + (query != null ? query.hashCode() : 0); result = 31 * result + (servers != null ? servers.hashCode() : 0); result = 31 * result + (parameters != null ? parameters.hashCode() : 0); result = 31 * result + ($ref != null ? $ref.hashCode() : 0); @@ -514,6 +552,7 @@ public String toString() { sb.append(" head: ").append(toIndentedString(head)).append("\n"); sb.append(" patch: ").append(toIndentedString(patch)).append("\n"); sb.append(" trace: ").append(toIndentedString(trace)).append("\n"); + sb.append(" query: ").append(toIndentedString(query)).append("\n"); sb.append(" servers: ").append(toIndentedString(servers)).append("\n"); sb.append(" parameters: ").append(toIndentedString(parameters)).append("\n"); sb.append(" $ref: ").append(toIndentedString($ref)).append("\n"); diff --git a/modules/swagger-models/src/test/java/io/swagger/v3/oas/models/PathItemTest.java b/modules/swagger-models/src/test/java/io/swagger/v3/oas/models/PathItemTest.java new file mode 100644 index 0000000000..b3d27656f9 --- /dev/null +++ b/modules/swagger-models/src/test/java/io/swagger/v3/oas/models/PathItemTest.java @@ -0,0 +1,80 @@ +package io.swagger.v3.oas.models; + +import org.testng.annotations.Test; + +import java.util.List; +import java.util.Map; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotEquals; +import static org.testng.Assert.assertSame; +import static org.testng.Assert.assertTrue; + +/** + * Tests for the OpenAPI 3.2 {@code query} HTTP method support on {@link PathItem}. + */ +public class PathItemTest { + + @Test + public void testQueryBuilderAndAccessors() { + Operation query = new Operation(); + PathItem pathItem = new PathItem().query(query); + + assertSame(pathItem.getQuery(), query); + + Operation other = new Operation(); + pathItem.setQuery(other); + assertSame(pathItem.getQuery(), other); + } + + @Test + public void testOperationSetterWithQueryMethod() { + Operation query = new Operation(); + PathItem pathItem = new PathItem(); + pathItem.operation(PathItem.HttpMethod.QUERY, query); + + assertSame(pathItem.getQuery(), query); + } + + @Test + public void testHttpMethodEnumContainsQuery() { + assertEquals(PathItem.HttpMethod.valueOf("QUERY"), PathItem.HttpMethod.QUERY); + } + + @Test + public void testReadOperationsIncludesQuery() { + Operation query = new Operation(); + PathItem pathItem = new PathItem().query(query); + + List operations = pathItem.readOperations(); + assertTrue(operations.contains(query)); + } + + @Test + public void testReadOperationsMapIncludesQuery() { + Operation query = new Operation(); + PathItem pathItem = new PathItem().query(query); + + Map map = pathItem.readOperationsMap(); + assertSame(map.get(PathItem.HttpMethod.QUERY), query); + } + + @Test + public void testEqualsAndHashCodeConsiderQuery() { + Operation query = new Operation().operationId("search"); + + PathItem passedObj = new PathItem().query(query); + PathItem createdObj = new PathItem().query(new Operation().operationId("search")); + PathItem emptyObj = new PathItem(); + + assertEquals(passedObj, createdObj); + assertEquals(passedObj.hashCode(), createdObj.hashCode()); + assertNotEquals(passedObj, emptyObj); + } + + @Test + public void testToStringContainsQuery() { + PathItem pathItem = new PathItem().query(new Operation()); + assertTrue(pathItem.toString().contains("query:")); + } +} From ede64400de2113fd182209edcdce4d3d26233b72 Mon Sep 17 00:00:00 2001 From: Elias Harb Date: Fri, 24 Jul 2026 23:18:37 +0200 Subject: [PATCH 2/3] feat(models): handle version gating for http query operation --- .../v3/core/jackson/mixin/PathItemMixin.java | 26 ++++++++++++ .../v3/core/util/ObjectMapperFactory.java | 5 ++- .../serialization/JsonSerializationTest.java | 42 +++++++++++++------ .../io/swagger/v3/oas/models/PathItem.java | 4 +- 4 files changed, 61 insertions(+), 16 deletions(-) create mode 100644 modules/swagger-core/src/main/java/io/swagger/v3/core/jackson/mixin/PathItemMixin.java diff --git a/modules/swagger-core/src/main/java/io/swagger/v3/core/jackson/mixin/PathItemMixin.java b/modules/swagger-core/src/main/java/io/swagger/v3/core/jackson/mixin/PathItemMixin.java new file mode 100644 index 0000000000..7e1ddf4b84 --- /dev/null +++ b/modules/swagger-core/src/main/java/io/swagger/v3/core/jackson/mixin/PathItemMixin.java @@ -0,0 +1,26 @@ +package io.swagger.v3.core.jackson.mixin; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnore; +import io.swagger.v3.oas.models.Operation; + +import java.util.Map; + +/** + * Mixin applied to {@link io.swagger.v3.oas.models.PathItem} for OpenAPI 3.0 and 3.1 mappers. + * + *

The {@code query} method is a fixed field of the Path Item Object only as of OpenAPI 3.2, + * so it is ignored here to keep 3.0 and 3.1 documents conformant. + */ +public abstract class PathItemMixin { + + @JsonAnyGetter + public abstract Map getExtensions(); + + @JsonAnySetter + public abstract void addExtension(String name, Object value); + + @JsonIgnore + public abstract Operation getQuery(); +} diff --git a/modules/swagger-core/src/main/java/io/swagger/v3/core/util/ObjectMapperFactory.java b/modules/swagger-core/src/main/java/io/swagger/v3/core/util/ObjectMapperFactory.java index a02539f54c..4eefee28ca 100644 --- a/modules/swagger-core/src/main/java/io/swagger/v3/core/util/ObjectMapperFactory.java +++ b/modules/swagger-core/src/main/java/io/swagger/v3/core/util/ObjectMapperFactory.java @@ -31,6 +31,7 @@ import io.swagger.v3.core.jackson.mixin.OpenAPI31Mixin; import io.swagger.v3.core.jackson.mixin.OpenAPIMixin; import io.swagger.v3.core.jackson.mixin.OperationMixin; +import io.swagger.v3.core.jackson.mixin.PathItemMixin; import io.swagger.v3.core.jackson.mixin.Schema31Mixin; import io.swagger.v3.core.jackson.mixin.SchemaConverterMixin; import io.swagger.v3.core.jackson.mixin.SchemaMixin; @@ -186,7 +187,7 @@ public JsonSerializer modifySerializer( sourceMixins.put(OAuthFlow.class, ExtensionsMixin.class); sourceMixins.put(OAuthFlows.class, ExtensionsMixin.class); sourceMixins.put(Operation.class, OperationMixin.class); - sourceMixins.put(PathItem.class, ExtensionsMixin.class); + sourceMixins.put(PathItem.class, PathItemMixin.class); sourceMixins.put(Paths.class, ExtensionsMixin.class); sourceMixins.put(Scopes.class, ExtensionsMixin.class); sourceMixins.put(Server.class, ExtensionsMixin.class); @@ -261,7 +262,7 @@ public static ObjectMapper createJsonConverter() { sourceMixins.put(OpenAPI.class, OpenAPIMixin.class); sourceMixins.put(Operation.class, OperationMixin.class); sourceMixins.put(Parameter.class, ExtensionsMixin.class); - sourceMixins.put(PathItem.class, ExtensionsMixin.class); + sourceMixins.put(PathItem.class, PathItemMixin.class); sourceMixins.put(Paths.class, ExtensionsMixin.class); sourceMixins.put(RequestBody.class, ExtensionsMixin.class); sourceMixins.put(Scopes.class, ExtensionsMixin.class); diff --git a/modules/swagger-core/src/test/java/io/swagger/v3/core/serialization/JsonSerializationTest.java b/modules/swagger-core/src/test/java/io/swagger/v3/core/serialization/JsonSerializationTest.java index 0bed350252..68594eb0f6 100644 --- a/modules/swagger-core/src/test/java/io/swagger/v3/core/serialization/JsonSerializationTest.java +++ b/modules/swagger-core/src/test/java/io/swagger/v3/core/serialization/JsonSerializationTest.java @@ -5,6 +5,7 @@ import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; import io.swagger.v3.core.matchers.SerializationMatchers; import io.swagger.v3.core.util.Json; +import io.swagger.v3.core.util.Json31; import io.swagger.v3.core.util.ObjectMapperFactory; import io.swagger.v3.core.util.ResourceUtils; import io.swagger.v3.core.util.Yaml; @@ -24,6 +25,7 @@ import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertNull; import static org.testng.Assert.assertTrue; public class JsonSerializationTest { @@ -45,29 +47,43 @@ public void testSerializeASpecWithPathReferences() throws Exception { } @Test - public void testSerializeQueryHttpMethod() throws Exception { + public void testQueryHttpMethodIsNotSerializedBeforeOpenAPI32() throws Exception { Operation queryOperation = new Operation() .operationId("searchPets") .responses(new ApiResponses() .addApiResponse("200", new ApiResponse().description("ok"))); - OpenAPI openAPI = new OpenAPI() - .path("/pets", new PathItem().query(queryOperation)); + PathItem pathItem = new PathItem() + .get(new Operation().operationId("listPets")) + .query(queryOperation); + OpenAPI openAPI = new OpenAPI().path("/pets", pathItem); + + // the model holds the operation ... + assertNotNull(openAPI.getPaths().get("/pets").getQuery()); + + // ... but "query" is a Path Item fixed field only as of OpenAPI 3.2, so neither the + // 3.0 nor the 3.1 mapper may emit it, while the other methods serialize as usual + for (String json : new String[]{ + Json.mapper().writeValueAsString(openAPI), + Json31.mapper().writeValueAsString(openAPI)}) { + assertFalse(json.contains("\"query\"")); + assertTrue(json.contains("\"listPets\"")); + assertFalse(json.contains("\"searchPets\"")); + } + } - String openAPIJson = Json.mapper().writeValueAsString(openAPI); + @Test + public void testQueryHttpMethodIsNotDeserializedBeforeOpenAPI32() throws Exception { - // the OpenAPI 3.2 "query" method must be serialized ... - assertTrue(openAPIJson.contains("\"query\"")); - // ... and unset methods must not leak (NON_NULL inclusion) - assertFalse(openAPIJson.contains("\"get\"")); + String json = "{\"openapi\":\"3.0.1\",\"paths\":{\"/pets\":{" + + "\"get\":{\"operationId\":\"listPets\"}," + + "\"query\":{\"operationId\":\"searchPets\"}}}}"; - OpenAPI rebuilt = Json.mapper().readValue(openAPIJson, OpenAPI.class); - PathItem rebuiltPath = rebuilt.getPaths().get("/pets"); + PathItem pathItem = Json.mapper().readValue(json, OpenAPI.class).getPaths().get("/pets"); - assertNotNull(rebuiltPath.getQuery()); - assertEquals(rebuiltPath.getQuery().getOperationId(), "searchPets"); - assertEquals(rebuiltPath, openAPI.getPaths().get("/pets")); + assertNotNull(pathItem.getGet()); + assertNull(pathItem.getQuery()); } @Test diff --git a/modules/swagger-models/src/main/java/io/swagger/v3/oas/models/PathItem.java b/modules/swagger-models/src/main/java/io/swagger/v3/oas/models/PathItem.java index 048ce172f2..16631a9d0e 100644 --- a/modules/swagger-models/src/main/java/io/swagger/v3/oas/models/PathItem.java +++ b/modules/swagger-models/src/main/java/io/swagger/v3/oas/models/PathItem.java @@ -227,7 +227,9 @@ public PathItem trace(Operation trace) { /** * returns the query property from a PathItem instance. * - *

The {@code query} HTTP method was introduced in OpenAPI 3.2. + *

The {@code query} HTTP method was introduced in OpenAPI 3.2. It is therefore not + * serialized by OpenAPI 3.0 and 3.1 mappers, which would otherwise emit a Path Item + * field that is not valid for those versions. * * @return Operation query * @since OpenAPI 3.2 From cc2e62579030c7f35c67c2411025f34913d66741 Mon Sep 17 00:00:00 2001 From: Elias Harb Date: Fri, 24 Jul 2026 18:03:45 +0200 Subject: [PATCH 3/3] feat(jaxrs2): support OpenAPI 3.2 QUERY method in annotation reade Route the "query" method in Reader.setPathItemOperation onto PathItem.query(), and include query operationIds in extractOperationIdFromPathItem. Adds QueryMethodTest. No new public API: ReaderUtils.getHttpMethodFromCustomAnnotations already resolves any @HttpMethod-meta-annotated annotation, so an application's own @QUERY binding maps with no further support. The @QUERY here is a test fixture standing in for that binding Refs swagger-api/swagger-parser#2248 (https://github.com/swagger-api/swagger-parser/issues/2248) --- .../java/io/swagger/v3/jaxrs2/Reader.java | 7 +++ .../io/swagger/v3/jaxrs2/QueryMethodTest.java | 55 +++++++++++++++++++ .../io/swagger/v3/jaxrs2/resources/QUERY.java | 23 ++++++++ .../jaxrs2/resources/QueryMethodResource.java | 19 +++++++ 4 files changed, 104 insertions(+) create mode 100644 modules/swagger-jaxrs2/src/test/java/io/swagger/v3/jaxrs2/QueryMethodTest.java create mode 100644 modules/swagger-jaxrs2/src/test/java/io/swagger/v3/jaxrs2/resources/QUERY.java create mode 100644 modules/swagger-jaxrs2/src/test/java/io/swagger/v3/jaxrs2/resources/QueryMethodResource.java diff --git a/modules/swagger-jaxrs2/src/main/java/io/swagger/v3/jaxrs2/Reader.java b/modules/swagger-jaxrs2/src/main/java/io/swagger/v3/jaxrs2/Reader.java index b15115aaf7..309b0be8a2 100644 --- a/modules/swagger-jaxrs2/src/main/java/io/swagger/v3/jaxrs2/Reader.java +++ b/modules/swagger-jaxrs2/src/main/java/io/swagger/v3/jaxrs2/Reader.java @@ -99,6 +99,7 @@ public class Reader implements OpenApiReader { private static final String TRACE_METHOD = "trace"; private static final String HEAD_METHOD = "head"; private static final String OPTIONS_METHOD = "options"; + private static final String QUERY_METHOD = "query"; public Reader() { this(new OpenAPI(), new Paths(), new LinkedHashSet<>(), new Components()); @@ -1397,6 +1398,9 @@ private void setPathItemOperation(PathItem pathItemObject, String method, Operat case OPTIONS_METHOD: pathItemObject.options(operation); break; + case QUERY_METHOD: + pathItemObject.query(operation); + break; default: // Do nothing here break; @@ -1565,6 +1569,9 @@ private Set extractOperationIdFromPathItem(PathItem path) { if (path.getPatch() != null && StringUtils.isNotBlank(path.getPatch().getOperationId())) { ids.add(path.getPatch().getOperationId()); } + if (path.getQuery() != null && StringUtils.isNotBlank(path.getQuery().getOperationId())) { + ids.add(path.getQuery().getOperationId()); + } return ids; } diff --git a/modules/swagger-jaxrs2/src/test/java/io/swagger/v3/jaxrs2/QueryMethodTest.java b/modules/swagger-jaxrs2/src/test/java/io/swagger/v3/jaxrs2/QueryMethodTest.java new file mode 100644 index 0000000000..b95ce019d3 --- /dev/null +++ b/modules/swagger-jaxrs2/src/test/java/io/swagger/v3/jaxrs2/QueryMethodTest.java @@ -0,0 +1,55 @@ +package io.swagger.v3.jaxrs2; + +import io.swagger.v3.core.util.Json; +import io.swagger.v3.core.util.Json31; +import io.swagger.v3.core.util.Yaml; +import io.swagger.v3.core.util.Yaml31; +import io.swagger.v3.jaxrs2.resources.QueryMethodResource; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.PathItem; +import org.testng.annotations.Test; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertNull; + +/** + * Verifies that the reader maps a custom {@code @HttpMethod("QUERY")} annotation + * (OpenAPI 3.2 query method) onto {@link PathItem#getQuery()}. + */ +public class QueryMethodTest { + + @Test(description = "read a resource declaring the OpenAPI 3.2 QUERY method") + public void testQueryHttpMethod() { + Reader reader = new Reader(new OpenAPI()); + OpenAPI openAPI = reader.read(QueryMethodResource.class); + + PathItem pathItem = openAPI.getPaths().get("/pets/search"); + assertNotNull(pathItem); + + assertNotNull(pathItem.getQuery()); + assertEquals(pathItem.getQuery().getOperationId(), "searchPets"); + + // the operation must land on query only, not leak onto other methods + assertNull(pathItem.getGet()); + assertNull(pathItem.getPost()); + } + + @Test(description = "a QUERY operation must not reach OpenAPI 3.0 or 3.1 output") + public void testQueryHttpMethodIsNotSerializedBeforeOpenAPI32() throws Exception { + Reader reader = new Reader(new OpenAPI()); + OpenAPI openAPI = reader.read(QueryMethodResource.class); + + // "query" is a Path Item fixed field only as of OpenAPI 3.2, so the operation the + // reader resolved stays in the model but is gated out of pre-3.2 documents + for (String serialized : new String[]{ + Yaml.mapper().writeValueAsString(openAPI), + Yaml31.mapper().writeValueAsString(openAPI), + Json.mapper().writeValueAsString(openAPI), + Json31.mapper().writeValueAsString(openAPI)}) { + assertFalse(serialized.contains("query")); + assertFalse(serialized.contains("searchPets")); + } + } +} diff --git a/modules/swagger-jaxrs2/src/test/java/io/swagger/v3/jaxrs2/resources/QUERY.java b/modules/swagger-jaxrs2/src/test/java/io/swagger/v3/jaxrs2/resources/QUERY.java new file mode 100644 index 0000000000..f390ae81ac --- /dev/null +++ b/modules/swagger-jaxrs2/src/test/java/io/swagger/v3/jaxrs2/resources/QUERY.java @@ -0,0 +1,23 @@ +package io.swagger.v3.jaxrs2.resources; + +import javax.ws.rs.HttpMethod; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Stands in for the {@code @QUERY} binding an application declares itself, since JAX-RS / + * Jakarta REST does not ship one for the OpenAPI 3.2 {@code QUERY} method. + * + *

It is meta-annotated with {@link HttpMethod} in the same way {@code javax.ws.rs.PATCH} is, + * which is all the reader needs: {@code ReaderUtils.getHttpMethodFromCustomAnnotations} resolves + * any such annotation to its lower-cased method name, which is then mapped onto + * {@link io.swagger.v3.oas.models.PathItem#getQuery()}. + */ +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@HttpMethod("QUERY") +public @interface QUERY { +} diff --git a/modules/swagger-jaxrs2/src/test/java/io/swagger/v3/jaxrs2/resources/QueryMethodResource.java b/modules/swagger-jaxrs2/src/test/java/io/swagger/v3/jaxrs2/resources/QueryMethodResource.java new file mode 100644 index 0000000000..23cea774bc --- /dev/null +++ b/modules/swagger-jaxrs2/src/test/java/io/swagger/v3/jaxrs2/resources/QueryMethodResource.java @@ -0,0 +1,19 @@ +package io.swagger.v3.jaxrs2.resources; + +import io.swagger.v3.oas.annotations.Operation; + +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Response; + +@Path("/pets") +public class QueryMethodResource { + + @QUERY + @Path("/search") + @Produces("application/json") + @Operation(operationId = "searchPets", summary = "Search pets") + public Response searchPets() { + return Response.ok().build(); + } +}