From dc4fea0ca284d351d66592c571d9cc0c3c903d23 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Aug 2024 19:30:17 +0000 Subject: [PATCH 01/17] Bump io.smallrye.config:smallrye-config-source-yaml in /devtools/gradle Bumps io.smallrye.config:smallrye-config-source-yaml from 3.8.3 to 3.9.1. --- updated-dependencies: - dependency-name: io.smallrye.config:smallrye-config-source-yaml dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] (cherry picked from commit bfe0dd2aeebec96695f5b5ea76584ad32333be4f) --- devtools/gradle/gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devtools/gradle/gradle/libs.versions.toml b/devtools/gradle/gradle/libs.versions.toml index 4ac165ca0f938..f69fccbea1780 100644 --- a/devtools/gradle/gradle/libs.versions.toml +++ b/devtools/gradle/gradle/libs.versions.toml @@ -3,7 +3,7 @@ plugin-publish = "1.2.1" # updating Kotlin here makes QuarkusPluginTest > shouldNotFailOnProjectDependenciesWithoutMain(Path) fail kotlin = "2.0.0" -smallrye-config = "3.8.3" +smallrye-config = "3.9.1" junit5 = "5.10.3" assertj = "3.26.3" From 5a206c76aeabe806e4b49d86d0afe8ed9a033ed4 Mon Sep 17 00:00:00 2001 From: Jimy Navarro Cordova Date: Mon, 29 Jul 2024 08:04:02 -0500 Subject: [PATCH 02/17] fix: considered the complete query in count query and links (cherry picked from commit 6a29458b61a968dd8337296157f888910a488b01) --- .../deployment/DataAccessImplementor.java | 6 +- .../EntityDataAccessImplementor.java | 11 +-- .../RepositoryDataAccessImplementor.java | 13 ++-- .../deployment/ResourceImplementor.java | 6 +- .../deployment/AbstractGetMethodTest.java | 67 ++++++++++++++++ .../deployment/DataAccessImplementor.java | 6 +- .../EntityDataAccessImplementor.java | 11 +-- .../RepositoryDataAccessImplementor.java | 13 ++-- .../deployment/ResourceImplementor.java | 6 +- .../deployment/AbstractGetMethodTest.java | 67 ++++++++++++++++ .../deployment/DataAccessImplementor.java | 13 +++- .../EntityDataAccessImplementor.java | 15 +++- .../RepositoryDataAccessImplementor.java | 20 +++-- .../deployment/ResourceImplementor.java | 10 ++- .../methods/ListMethodImplementor.java | 67 +++++----------- .../utils/PaginationImplementor.java | 35 +++++++-- .../deployment/utils/QueryImplementor.java | 78 +++++++++++++++++++ .../RepositoryMethodsImplementor.java | 2 +- 18 files changed, 349 insertions(+), 97 deletions(-) create mode 100644 extensions/panache/rest-data-panache/deployment/src/main/java/io/quarkus/rest/data/panache/deployment/utils/QueryImplementor.java diff --git a/extensions/panache/hibernate-orm-rest-data-panache/deployment/src/main/java/io/quarkus/hibernate/orm/rest/data/panache/deployment/DataAccessImplementor.java b/extensions/panache/hibernate-orm-rest-data-panache/deployment/src/main/java/io/quarkus/hibernate/orm/rest/data/panache/deployment/DataAccessImplementor.java index b944fb334f02a..67235ee93dac4 100644 --- a/extensions/panache/hibernate-orm-rest-data-panache/deployment/src/main/java/io/quarkus/hibernate/orm/rest/data/panache/deployment/DataAccessImplementor.java +++ b/extensions/panache/hibernate-orm-rest-data-panache/deployment/src/main/java/io/quarkus/hibernate/orm/rest/data/panache/deployment/DataAccessImplementor.java @@ -91,10 +91,12 @@ ResultHandle findAll(BytecodeCreator creator, ResultHandle page, ResultHandle so * Available number of pages given a page instance. * * @param creator Bytecode creator that should be used for implementation. - * @param page Page instance. + * @param page Page instance that should be used in a query. + * @param query HQL query to list entities. + * @param queryParams Map of parameters to use by the HQL query. * @return int page count. */ - ResultHandle pageCount(BytecodeCreator creator, ResultHandle page); + ResultHandle pageCount(BytecodeCreator creator, ResultHandle page, ResultHandle query, ResultHandle queryParams); /** * return the total number of entities. diff --git a/extensions/panache/hibernate-orm-rest-data-panache/deployment/src/main/java/io/quarkus/hibernate/orm/rest/data/panache/deployment/EntityDataAccessImplementor.java b/extensions/panache/hibernate-orm-rest-data-panache/deployment/src/main/java/io/quarkus/hibernate/orm/rest/data/panache/deployment/EntityDataAccessImplementor.java index 3e17564a90f25..9edb9ba4ada8a 100644 --- a/extensions/panache/hibernate-orm-rest-data-panache/deployment/src/main/java/io/quarkus/hibernate/orm/rest/data/panache/deployment/EntityDataAccessImplementor.java +++ b/extensions/panache/hibernate-orm-rest-data-panache/deployment/src/main/java/io/quarkus/hibernate/orm/rest/data/panache/deployment/EntityDataAccessImplementor.java @@ -112,14 +112,15 @@ public ResultHandle deleteById(BytecodeCreator creator, ResultHandle id) { } /** - * Implements Entity.findAll().page(page).pageCount() + * Implements Entity.find(query, params).page(page).pageCount() */ @Override - public ResultHandle pageCount(BytecodeCreator creator, ResultHandle page) { - ResultHandle query = creator.invokeStaticMethod(ofMethod(entityClassName, "findAll", PanacheQuery.class)); - creator.invokeInterfaceMethod(ofMethod(PanacheQuery.class, "page", PanacheQuery.class, Page.class), query, + public ResultHandle pageCount(BytecodeCreator creator, ResultHandle page, ResultHandle query, ResultHandle queryParams) { + ResultHandle panacheQuery = creator.invokeStaticMethod(ofMethod(entityClassName, "find", PanacheQuery.class, + String.class, Map.class), query, queryParams); + creator.invokeInterfaceMethod(ofMethod(PanacheQuery.class, "page", PanacheQuery.class, Page.class), panacheQuery, page); - return creator.invokeInterfaceMethod(ofMethod(PanacheQuery.class, "pageCount", int.class), query); + return creator.invokeInterfaceMethod(ofMethod(PanacheQuery.class, "pageCount", int.class), panacheQuery); } /** diff --git a/extensions/panache/hibernate-orm-rest-data-panache/deployment/src/main/java/io/quarkus/hibernate/orm/rest/data/panache/deployment/RepositoryDataAccessImplementor.java b/extensions/panache/hibernate-orm-rest-data-panache/deployment/src/main/java/io/quarkus/hibernate/orm/rest/data/panache/deployment/RepositoryDataAccessImplementor.java index 2f560610164cb..bbe9c1944b2d3 100644 --- a/extensions/panache/hibernate-orm-rest-data-panache/deployment/src/main/java/io/quarkus/hibernate/orm/rest/data/panache/deployment/RepositoryDataAccessImplementor.java +++ b/extensions/panache/hibernate-orm-rest-data-panache/deployment/src/main/java/io/quarkus/hibernate/orm/rest/data/panache/deployment/RepositoryDataAccessImplementor.java @@ -119,14 +119,15 @@ public ResultHandle deleteById(BytecodeCreator creator, ResultHandle id) { } /** - * Implements repository.findAll().page(page).pageCount() + * Implements repository.find(query, params).page(page).pageCount() */ @Override - public ResultHandle pageCount(BytecodeCreator creator, ResultHandle page) { - ResultHandle query = creator.invokeInterfaceMethod(ofMethod(PanacheRepositoryBase.class, "findAll", PanacheQuery.class), - getRepositoryInstance(creator)); - creator.invokeInterfaceMethod(ofMethod(PanacheQuery.class, "page", PanacheQuery.class, Page.class), query, page); - return creator.invokeInterfaceMethod(ofMethod(PanacheQuery.class, "pageCount", int.class), query); + public ResultHandle pageCount(BytecodeCreator creator, ResultHandle page, ResultHandle query, ResultHandle queryParams) { + ResultHandle panacheQuery = creator + .invokeInterfaceMethod(ofMethod(PanacheRepositoryBase.class, "find", PanacheQuery.class, + String.class, Map.class), getRepositoryInstance(creator), query, queryParams); + creator.invokeInterfaceMethod(ofMethod(PanacheQuery.class, "page", PanacheQuery.class, Page.class), panacheQuery, page); + return creator.invokeInterfaceMethod(ofMethod(PanacheQuery.class, "pageCount", int.class), panacheQuery); } /** diff --git a/extensions/panache/hibernate-orm-rest-data-panache/deployment/src/main/java/io/quarkus/hibernate/orm/rest/data/panache/deployment/ResourceImplementor.java b/extensions/panache/hibernate-orm-rest-data-panache/deployment/src/main/java/io/quarkus/hibernate/orm/rest/data/panache/deployment/ResourceImplementor.java index 25b964f53591e..54173496437c6 100644 --- a/extensions/panache/hibernate-orm-rest-data-panache/deployment/src/main/java/io/quarkus/hibernate/orm/rest/data/panache/deployment/ResourceImplementor.java +++ b/extensions/panache/hibernate-orm-rest-data-panache/deployment/src/main/java/io/quarkus/hibernate/orm/rest/data/panache/deployment/ResourceImplementor.java @@ -119,9 +119,11 @@ private void implementListWithQuery(ClassCreator classCreator, DataAccessImpleme */ private void implementListPageCount(ClassCreator classCreator, DataAccessImplementor dataAccessImplementor) { MethodCreator methodCreator = classCreator.getMethodCreator(Constants.PAGE_COUNT_METHOD_PREFIX + "list", int.class, - Page.class); + Page.class, String.class, Map.class); ResultHandle page = methodCreator.getMethodParam(0); - methodCreator.returnValue(dataAccessImplementor.pageCount(methodCreator, page)); + ResultHandle query = methodCreator.getMethodParam(1); + ResultHandle queryParams = methodCreator.getMethodParam(2); + methodCreator.returnValue(dataAccessImplementor.pageCount(methodCreator, page, query, queryParams)); methodCreator.close(); } diff --git a/extensions/panache/hibernate-orm-rest-data-panache/deployment/src/test/java/io/quarkus/hibernate/orm/rest/data/panache/deployment/AbstractGetMethodTest.java b/extensions/panache/hibernate-orm-rest-data-panache/deployment/src/test/java/io/quarkus/hibernate/orm/rest/data/panache/deployment/AbstractGetMethodTest.java index e50a90dd79848..68b929dbf282a 100644 --- a/extensions/panache/hibernate-orm-rest-data-panache/deployment/src/test/java/io/quarkus/hibernate/orm/rest/data/panache/deployment/AbstractGetMethodTest.java +++ b/extensions/panache/hibernate-orm-rest-data-panache/deployment/src/test/java/io/quarkus/hibernate/orm/rest/data/panache/deployment/AbstractGetMethodTest.java @@ -14,6 +14,8 @@ import jakarta.ws.rs.core.Link; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; import io.restassured.http.Header; import io.restassured.response.Response; @@ -416,4 +418,69 @@ void shouldListEmptyTables() { .when().get("/empty-list-items") .then().statusCode(200); } + + @ParameterizedTest + @CsvSource({ + "page,0", + "size,1", + "name,first", + "collection.id,full" + }) + void shouldShowSpecificParameterInLinkHeaders(String queryParamName, String queryParamValue) { + Response response = given().accept("application/json") + .when() + .queryParam(queryParamName, queryParamValue) + .get("/items") + .thenReturn(); + + assertThat(response.getStatusCode()).isEqualTo(200); + List links = response.getHeaders().getList("Link") + .stream() + .map(header -> Link.valueOf(header.getValue())) + .toList(); + assertThat(links).allMatch(link -> link.getUri().getQuery() + .contains(String.format("%s=%s", queryParamName, queryParamValue))); + } + + @Test + void shouldShowAllPaginationAndCustomQueryParametersInLinkHeaders() { + Response response = given().accept("application/json") + .when() + .queryParam("page", "0") + .queryParam("size", "3") + .queryParam("name", "first") + .queryParam("namedQuery", "Item.containsInName") + .get("/items") + .thenReturn(); + + assertThat(response.getStatusCode()).isEqualTo(200); + List links = response.getHeaders().getList("Link") + .stream() + .map(header -> Link.valueOf(header.getValue())) + .toList(); + assertThat(links).allMatch(link -> link.getUri().getQuery() + .contains("page=0&size=3&namedQuery=Item.containsInName&name=first")); + } + + @Test + void shouldShowAllPaginationAndFilteringParametersInLinkHeaders() { + Response response = given().accept("application/json") + .when() + .queryParam("page", "0") + .queryParam("size", "1") + .queryParam("name", "first") + .queryParam("collection.id", "full") + .get("/items") + .thenReturn(); + + assertThat(response.getStatusCode()).isEqualTo(200); + List links = response.getHeaders().getList("Link") + .stream() + .map(header -> Link.valueOf(header.getValue())) + .toList(); + assertThat(links).allMatch(link -> { + var query = link.getUri().getQuery(); + return query.contains("page=0&size=1") && query.contains("name=first") && query.contains("collection.id=full"); + }); + } } diff --git a/extensions/panache/hibernate-reactive-rest-data-panache/deployment/src/main/java/io/quarkus/hibernate/reactive/rest/data/panache/deployment/DataAccessImplementor.java b/extensions/panache/hibernate-reactive-rest-data-panache/deployment/src/main/java/io/quarkus/hibernate/reactive/rest/data/panache/deployment/DataAccessImplementor.java index 9d3fec3a0b40a..eed594a96c95d 100644 --- a/extensions/panache/hibernate-reactive-rest-data-panache/deployment/src/main/java/io/quarkus/hibernate/reactive/rest/data/panache/deployment/DataAccessImplementor.java +++ b/extensions/panache/hibernate-reactive-rest-data-panache/deployment/src/main/java/io/quarkus/hibernate/reactive/rest/data/panache/deployment/DataAccessImplementor.java @@ -91,10 +91,12 @@ ResultHandle findAll(BytecodeCreator creator, ResultHandle page, ResultHandle so * Available number of pages given a page instance. * * @param creator Bytecode creator that should be used for implementation. - * @param page Page instance. + * @param page Page instance that should be used in a query. + * @param query HQL query to list entities. + * @param queryParams Map of parameters to use by the HQL query. * @return int page count. */ - ResultHandle pageCount(BytecodeCreator creator, ResultHandle page); + ResultHandle pageCount(BytecodeCreator creator, ResultHandle page, ResultHandle query, ResultHandle queryParams); /** * return the total number of entities. diff --git a/extensions/panache/hibernate-reactive-rest-data-panache/deployment/src/main/java/io/quarkus/hibernate/reactive/rest/data/panache/deployment/EntityDataAccessImplementor.java b/extensions/panache/hibernate-reactive-rest-data-panache/deployment/src/main/java/io/quarkus/hibernate/reactive/rest/data/panache/deployment/EntityDataAccessImplementor.java index ca0d84fbe5cff..74345c3664983 100644 --- a/extensions/panache/hibernate-reactive-rest-data-panache/deployment/src/main/java/io/quarkus/hibernate/reactive/rest/data/panache/deployment/EntityDataAccessImplementor.java +++ b/extensions/panache/hibernate-reactive-rest-data-panache/deployment/src/main/java/io/quarkus/hibernate/reactive/rest/data/panache/deployment/EntityDataAccessImplementor.java @@ -113,14 +113,15 @@ public ResultHandle deleteById(BytecodeCreator creator, ResultHandle id) { } /** - * Implements Entity.findAll().page(page).pageCount() + * Implements Entity.find(query, params).page(page).pageCount() */ @Override - public ResultHandle pageCount(BytecodeCreator creator, ResultHandle page) { - ResultHandle query = creator.invokeStaticMethod(ofMethod(entityClassName, "findAll", PanacheQuery.class)); - creator.invokeInterfaceMethod(ofMethod(PanacheQuery.class, "page", PanacheQuery.class, Page.class), query, + public ResultHandle pageCount(BytecodeCreator creator, ResultHandle page, ResultHandle query, ResultHandle queryParams) { + ResultHandle panacheQuery = creator.invokeStaticMethod(ofMethod(entityClassName, "find", PanacheQuery.class, + String.class, Map.class), query, queryParams); + creator.invokeInterfaceMethod(ofMethod(PanacheQuery.class, "page", PanacheQuery.class, Page.class), panacheQuery, page); - return creator.invokeInterfaceMethod(ofMethod(PanacheQuery.class, "pageCount", Uni.class), query); + return creator.invokeInterfaceMethod(ofMethod(PanacheQuery.class, "pageCount", Uni.class), panacheQuery); } /** diff --git a/extensions/panache/hibernate-reactive-rest-data-panache/deployment/src/main/java/io/quarkus/hibernate/reactive/rest/data/panache/deployment/RepositoryDataAccessImplementor.java b/extensions/panache/hibernate-reactive-rest-data-panache/deployment/src/main/java/io/quarkus/hibernate/reactive/rest/data/panache/deployment/RepositoryDataAccessImplementor.java index 603ce94caec84..f1e9078f66948 100644 --- a/extensions/panache/hibernate-reactive-rest-data-panache/deployment/src/main/java/io/quarkus/hibernate/reactive/rest/data/panache/deployment/RepositoryDataAccessImplementor.java +++ b/extensions/panache/hibernate-reactive-rest-data-panache/deployment/src/main/java/io/quarkus/hibernate/reactive/rest/data/panache/deployment/RepositoryDataAccessImplementor.java @@ -123,14 +123,15 @@ public ResultHandle deleteById(BytecodeCreator creator, ResultHandle id) { } /** - * Implements repository.findAll().page(page).pageCount() + * Implements repository.find(query, params).page(page).pageCount() */ @Override - public ResultHandle pageCount(BytecodeCreator creator, ResultHandle page) { - ResultHandle query = creator.invokeInterfaceMethod(ofMethod(PanacheRepositoryBase.class, "findAll", PanacheQuery.class), - getRepositoryInstance(creator)); - creator.invokeInterfaceMethod(ofMethod(PanacheQuery.class, "page", PanacheQuery.class, Page.class), query, page); - return creator.invokeInterfaceMethod(ofMethod(PanacheQuery.class, "pageCount", Uni.class), query); + public ResultHandle pageCount(BytecodeCreator creator, ResultHandle page, ResultHandle query, ResultHandle queryParams) { + ResultHandle panacheQuery = creator + .invokeInterfaceMethod(ofMethod(PanacheRepositoryBase.class, "find", PanacheQuery.class, + String.class, Map.class), getRepositoryInstance(creator), query, queryParams); + creator.invokeInterfaceMethod(ofMethod(PanacheQuery.class, "page", PanacheQuery.class, Page.class), panacheQuery, page); + return creator.invokeInterfaceMethod(ofMethod(PanacheQuery.class, "pageCount", Uni.class), panacheQuery); } /** diff --git a/extensions/panache/hibernate-reactive-rest-data-panache/deployment/src/main/java/io/quarkus/hibernate/reactive/rest/data/panache/deployment/ResourceImplementor.java b/extensions/panache/hibernate-reactive-rest-data-panache/deployment/src/main/java/io/quarkus/hibernate/reactive/rest/data/panache/deployment/ResourceImplementor.java index 17d2aab4f6759..6192eb12bcf73 100644 --- a/extensions/panache/hibernate-reactive-rest-data-panache/deployment/src/main/java/io/quarkus/hibernate/reactive/rest/data/panache/deployment/ResourceImplementor.java +++ b/extensions/panache/hibernate-reactive-rest-data-panache/deployment/src/main/java/io/quarkus/hibernate/reactive/rest/data/panache/deployment/ResourceImplementor.java @@ -130,9 +130,11 @@ private void implementCount(ClassCreator classCreator, DataAccessImplementor dat */ private void implementListPageCount(ClassCreator classCreator, DataAccessImplementor dataAccessImplementor) { MethodCreator methodCreator = classCreator.getMethodCreator(Constants.PAGE_COUNT_METHOD_PREFIX + "list", Uni.class, - Page.class); + Page.class, String.class, Map.class); ResultHandle page = methodCreator.getMethodParam(0); - methodCreator.returnValue(dataAccessImplementor.pageCount(methodCreator, page)); + ResultHandle query = methodCreator.getMethodParam(1); + ResultHandle queryParams = methodCreator.getMethodParam(2); + methodCreator.returnValue(dataAccessImplementor.pageCount(methodCreator, page, query, queryParams)); methodCreator.close(); } diff --git a/extensions/panache/hibernate-reactive-rest-data-panache/deployment/src/test/java/io/quarkus/hibernate/reactive/rest/data/panache/deployment/AbstractGetMethodTest.java b/extensions/panache/hibernate-reactive-rest-data-panache/deployment/src/test/java/io/quarkus/hibernate/reactive/rest/data/panache/deployment/AbstractGetMethodTest.java index 77671de648648..80ae2cb4f61a2 100644 --- a/extensions/panache/hibernate-reactive-rest-data-panache/deployment/src/test/java/io/quarkus/hibernate/reactive/rest/data/panache/deployment/AbstractGetMethodTest.java +++ b/extensions/panache/hibernate-reactive-rest-data-panache/deployment/src/test/java/io/quarkus/hibernate/reactive/rest/data/panache/deployment/AbstractGetMethodTest.java @@ -14,6 +14,8 @@ import jakarta.ws.rs.core.Link; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; import io.restassured.http.Header; import io.restassured.response.Response; @@ -396,4 +398,69 @@ void shouldListEmptyTables() { .when().get("/empty-list-items") .then().statusCode(200); } + + @ParameterizedTest + @CsvSource({ + "page,0", + "size,1", + "name,first", + "collection.id,full" + }) + void shouldShowSpecificParameterInLinkHeaders(String queryParamName, String queryParamValue) { + Response response = given().accept("application/json") + .when() + .queryParam(queryParamName, queryParamValue) + .get("/items") + .thenReturn(); + + assertThat(response.getStatusCode()).isEqualTo(200); + List links = response.getHeaders().getList("Link") + .stream() + .map(header -> Link.valueOf(header.getValue())) + .toList(); + assertThat(links).allMatch(link -> link.getUri().getQuery() + .contains(String.format("%s=%s", queryParamName, queryParamValue))); + } + + @Test + void shouldShowAllPaginationAndCustomQueryParametersInLinkHeaders() { + Response response = given().accept("application/json") + .when() + .queryParam("page", "0") + .queryParam("size", "3") + .queryParam("name", "first") + .queryParam("namedQuery", "Item.containsInName") + .get("/items") + .thenReturn(); + + assertThat(response.getStatusCode()).isEqualTo(200); + List links = response.getHeaders().getList("Link") + .stream() + .map(header -> Link.valueOf(header.getValue())) + .toList(); + assertThat(links).allMatch(link -> link.getUri().getQuery() + .contains("page=0&size=3&namedQuery=Item.containsInName&name=first")); + } + + @Test + void shouldShowAllPaginationAndFilteringParametersInLinkHeaders() { + Response response = given().accept("application/json") + .when() + .queryParam("page", "0") + .queryParam("size", "1") + .queryParam("name", "first") + .queryParam("collection.id", "full") + .get("/items") + .thenReturn(); + + assertThat(response.getStatusCode()).isEqualTo(200); + List links = response.getHeaders().getList("Link") + .stream() + .map(header -> Link.valueOf(header.getValue())) + .toList(); + assertThat(links).allMatch(link -> { + var query = link.getUri().getQuery(); + return query.contains("page=0&size=1") && query.contains("name=first") && query.contains("collection.id=full"); + }); + } } diff --git a/extensions/panache/mongodb-rest-data-panache/deployment/src/main/java/io/quarkus/mongodb/rest/data/panache/deployment/DataAccessImplementor.java b/extensions/panache/mongodb-rest-data-panache/deployment/src/main/java/io/quarkus/mongodb/rest/data/panache/deployment/DataAccessImplementor.java index a383691e2536a..53964149243b2 100644 --- a/extensions/panache/mongodb-rest-data-panache/deployment/src/main/java/io/quarkus/mongodb/rest/data/panache/deployment/DataAccessImplementor.java +++ b/extensions/panache/mongodb-rest-data-panache/deployment/src/main/java/io/quarkus/mongodb/rest/data/panache/deployment/DataAccessImplementor.java @@ -91,7 +91,18 @@ ResultHandle findAll(BytecodeCreator creator, ResultHandle page, ResultHandle so * Available number of pages given a page instance. * * @param creator Bytecode creator that should be used for implementation. - * @param page Page instance. + * @param page Page instance that should be used in a query. Might be null if pagination is disabled. + * @param query HQL query to list entities. + * @param queryParams Map of parameters to use by the HQL query. + * @return int page count. + */ + ResultHandle pageCount(BytecodeCreator creator, ResultHandle page, ResultHandle query, ResultHandle queryParams); + + /** + * Available number of pages given a page instance. + * + * @param creator Bytecode creator that should be used for implementation. + * @param page Page instance that should be used in a query. Might be null if pagination is disabled. * @return int page count. */ ResultHandle pageCount(BytecodeCreator creator, ResultHandle page); diff --git a/extensions/panache/mongodb-rest-data-panache/deployment/src/main/java/io/quarkus/mongodb/rest/data/panache/deployment/EntityDataAccessImplementor.java b/extensions/panache/mongodb-rest-data-panache/deployment/src/main/java/io/quarkus/mongodb/rest/data/panache/deployment/EntityDataAccessImplementor.java index 6e730e2eebe4a..2cd0b9dc6b483 100644 --- a/extensions/panache/mongodb-rest-data-panache/deployment/src/main/java/io/quarkus/mongodb/rest/data/panache/deployment/EntityDataAccessImplementor.java +++ b/extensions/panache/mongodb-rest-data-panache/deployment/src/main/java/io/quarkus/mongodb/rest/data/panache/deployment/EntityDataAccessImplementor.java @@ -88,11 +88,20 @@ public ResultHandle deleteById(BytecodeCreator creator, ResultHandle id) { return creator.invokeStaticMethod(ofMethod(entityClassName, "deleteById", boolean.class, Object.class), id); } + @Override + public ResultHandle pageCount(BytecodeCreator creator, ResultHandle page, ResultHandle query, ResultHandle queryParams) { + ResultHandle panacheQuery = creator.invokeStaticMethod(ofMethod(entityClassName, "find", PanacheQuery.class, + String.class, Map.class), query, queryParams); + creator.invokeInterfaceMethod(ofMethod(PanacheQuery.class, "page", PanacheQuery.class, Page.class), panacheQuery, + page); + return creator.invokeInterfaceMethod(ofMethod(PanacheQuery.class, "pageCount", int.class), panacheQuery); + } + @Override public ResultHandle pageCount(BytecodeCreator creator, ResultHandle page) { - ResultHandle query = creator.invokeStaticMethod(ofMethod(entityClassName, "findAll", PanacheQuery.class)); - creator.invokeInterfaceMethod(ofMethod(PanacheQuery.class, "page", PanacheQuery.class, Page.class), query, + ResultHandle panacheQuery = creator.invokeStaticMethod(ofMethod(entityClassName, "findAll", PanacheQuery.class)); + creator.invokeInterfaceMethod(ofMethod(PanacheQuery.class, "page", PanacheQuery.class, Page.class), panacheQuery, page); - return creator.invokeInterfaceMethod(ofMethod(PanacheQuery.class, "pageCount", int.class), query); + return creator.invokeInterfaceMethod(ofMethod(PanacheQuery.class, "pageCount", int.class), panacheQuery); } } diff --git a/extensions/panache/mongodb-rest-data-panache/deployment/src/main/java/io/quarkus/mongodb/rest/data/panache/deployment/RepositoryDataAccessImplementor.java b/extensions/panache/mongodb-rest-data-panache/deployment/src/main/java/io/quarkus/mongodb/rest/data/panache/deployment/RepositoryDataAccessImplementor.java index be986926f2690..c0bfc3cccee45 100644 --- a/extensions/panache/mongodb-rest-data-panache/deployment/src/main/java/io/quarkus/mongodb/rest/data/panache/deployment/RepositoryDataAccessImplementor.java +++ b/extensions/panache/mongodb-rest-data-panache/deployment/src/main/java/io/quarkus/mongodb/rest/data/panache/deployment/RepositoryDataAccessImplementor.java @@ -98,14 +98,22 @@ public ResultHandle deleteById(BytecodeCreator creator, ResultHandle id) { getRepositoryInstance(creator), id); } + @Override + public ResultHandle pageCount(BytecodeCreator creator, ResultHandle page, ResultHandle query, ResultHandle queryParams) { + ResultHandle panacheQuery = creator + .invokeInterfaceMethod(ofMethod(PanacheMongoRepositoryBase.class, "find", PanacheQuery.class, + String.class, Map.class), getRepositoryInstance(creator), query, queryParams); + creator.invokeInterfaceMethod(ofMethod(PanacheQuery.class, "page", PanacheQuery.class, Page.class), panacheQuery, page); + return creator.invokeInterfaceMethod(ofMethod(PanacheQuery.class, "pageCount", int.class), panacheQuery); + } + @Override public ResultHandle pageCount(BytecodeCreator creator, ResultHandle page) { - ResultHandle query = creator.invokeInterfaceMethod( - ofMethod(PanacheMongoRepositoryBase.class, "findAll", PanacheQuery.class), - getRepositoryInstance(creator)); - creator.invokeInterfaceMethod(ofMethod(PanacheQuery.class, "page", PanacheQuery.class, Page.class), query, - page); - return creator.invokeInterfaceMethod(ofMethod(PanacheQuery.class, "pageCount", int.class), query); + ResultHandle panacheQuery = creator + .invokeInterfaceMethod(ofMethod(PanacheMongoRepositoryBase.class, "findAll", PanacheQuery.class), + getRepositoryInstance(creator)); + creator.invokeInterfaceMethod(ofMethod(PanacheQuery.class, "page", PanacheQuery.class, Page.class), panacheQuery, page); + return creator.invokeInterfaceMethod(ofMethod(PanacheQuery.class, "pageCount", int.class), panacheQuery); } private ResultHandle getRepositoryInstance(BytecodeCreator creator) { diff --git a/extensions/panache/mongodb-rest-data-panache/deployment/src/main/java/io/quarkus/mongodb/rest/data/panache/deployment/ResourceImplementor.java b/extensions/panache/mongodb-rest-data-panache/deployment/src/main/java/io/quarkus/mongodb/rest/data/panache/deployment/ResourceImplementor.java index 8f7dd2f527fe6..f327bfb74aaca 100644 --- a/extensions/panache/mongodb-rest-data-panache/deployment/src/main/java/io/quarkus/mongodb/rest/data/panache/deployment/ResourceImplementor.java +++ b/extensions/panache/mongodb-rest-data-panache/deployment/src/main/java/io/quarkus/mongodb/rest/data/panache/deployment/ResourceImplementor.java @@ -101,9 +101,15 @@ private void implementListWithQuery(BytecodeCreator body, ResultHandle page, Res private void implementListPageCount(ClassCreator classCreator, DataAccessImplementor dataAccessImplementor) { MethodCreator methodCreator = classCreator.getMethodCreator(Constants.PAGE_COUNT_METHOD_PREFIX + "list", int.class, - Page.class); + Page.class, String.class, Map.class); ResultHandle page = methodCreator.getMethodParam(0); - methodCreator.returnValue(dataAccessImplementor.pageCount(methodCreator, page)); + ResultHandle query = methodCreator.getMethodParam(1); + ResultHandle queryParams = methodCreator.getMethodParam(2); + ResultHandle hasQuery = methodCreator.invokeVirtualMethod(ofMethod(String.class, "isEmpty", boolean.class), query); + BranchResult hasQueryBranch = methodCreator.ifTrue(hasQuery); + hasQueryBranch.trueBranch().returnValue(dataAccessImplementor.pageCount(hasQueryBranch.trueBranch(), page)); + hasQueryBranch.falseBranch().returnValue(dataAccessImplementor.pageCount(hasQueryBranch.falseBranch(), page, query, + queryParams)); methodCreator.close(); } diff --git a/extensions/panache/rest-data-panache/deployment/src/main/java/io/quarkus/rest/data/panache/deployment/methods/ListMethodImplementor.java b/extensions/panache/rest-data-panache/deployment/src/main/java/io/quarkus/rest/data/panache/deployment/methods/ListMethodImplementor.java index 99abbdabdc13e..09905f1b89426 100644 --- a/extensions/panache/rest-data-panache/deployment/src/main/java/io/quarkus/rest/data/panache/deployment/methods/ListMethodImplementor.java +++ b/extensions/panache/rest-data-panache/deployment/src/main/java/io/quarkus/rest/data/panache/deployment/methods/ListMethodImplementor.java @@ -9,7 +9,6 @@ import static io.quarkus.arc.processor.DotNames.LONG; import static io.quarkus.arc.processor.DotNames.SHORT; import static io.quarkus.arc.processor.DotNames.STRING; -import static io.quarkus.gizmo.MethodDescriptor.ofConstructor; import static io.quarkus.gizmo.MethodDescriptor.ofMethod; import static io.quarkus.gizmo.Type.classType; import static io.quarkus.gizmo.Type.intType; @@ -36,7 +35,6 @@ import io.quarkus.deployment.Capabilities; import io.quarkus.gizmo.AnnotatedElement; import io.quarkus.gizmo.AssignableResultHandle; -import io.quarkus.gizmo.BranchResult; import io.quarkus.gizmo.BytecodeCreator; import io.quarkus.gizmo.ClassCreator; import io.quarkus.gizmo.FieldDescriptor; @@ -50,6 +48,7 @@ import io.quarkus.rest.data.panache.deployment.ResourceMetadata; import io.quarkus.rest.data.panache.deployment.properties.ResourceProperties; import io.quarkus.rest.data.panache.deployment.utils.PaginationImplementor; +import io.quarkus.rest.data.panache.deployment.utils.QueryImplementor; import io.quarkus.rest.data.panache.deployment.utils.SignatureMethodCreator; import io.quarkus.rest.data.panache.deployment.utils.SortImplementor; import io.quarkus.rest.data.panache.deployment.utils.UniImplementor; @@ -67,6 +66,7 @@ public class ListMethodImplementor extends StandardMethodImplementor { private final PaginationImplementor paginationImplementor = new PaginationImplementor(); private final SortImplementor sortImplementor = new SortImplementor(); + private final QueryImplementor queryImplementor = new QueryImplementor(); public ListMethodImplementor(Capabilities capabilities) { super(capabilities); @@ -229,27 +229,22 @@ private void implementPaged(ClassCreator classCreator, ResourceMetadata resource if (isNotReactivePanache()) { TryBlock tryBlock = implementTryBlock(methodCreator, EXCEPTION_MESSAGE); - ResultHandle pageCount = tryBlock.invokeVirtualMethod( - ofMethod(resourceMetadata.getResourceClass(), Constants.PAGE_COUNT_METHOD_PREFIX + RESOURCE_METHOD_NAME, - int.class, Page.class), - resource, page); - - ResultHandle links = paginationImplementor.getLinks(tryBlock, uriInfo, page, pageCount); + ResultHandle pageCount = pageCount(tryBlock, resourceMetadata, resource, page, namedQuery, fieldValues, int.class); + ResultHandle links = paginationImplementor.getLinks(tryBlock, uriInfo, page, pageCount, fieldValues, namedQuery); ResultHandle entities = list(tryBlock, resourceMetadata, resource, page, sort, namedQuery, fieldValues); // Return response returnValueWithLinks(tryBlock, resourceMetadata, resourceProperties, entities, links); tryBlock.close(); } else { - ResultHandle uniPageCount = methodCreator.invokeVirtualMethod( - ofMethod(resourceMetadata.getResourceClass(), Constants.PAGE_COUNT_METHOD_PREFIX + RESOURCE_METHOD_NAME, - Uni.class, Page.class), - resource, page); + ResultHandle uniPageCount = pageCount(methodCreator, resourceMetadata, resource, page, namedQuery, fieldValues, + Uni.class); methodCreator.returnValue(UniImplementor.flatMap(methodCreator, uniPageCount, EXCEPTION_MESSAGE, (body, pageCount) -> { ResultHandle pageCountAsInt = body.checkCast(pageCount, Integer.class); - ResultHandle links = paginationImplementor.getLinks(body, uriInfo, page, pageCountAsInt); + ResultHandle links = paginationImplementor.getLinks(body, uriInfo, page, pageCountAsInt, fieldValues, + namedQuery); ResultHandle uniEntities = list(body, resourceMetadata, resource, page, sort, namedQuery, fieldValues); body.returnValue(UniImplementor.map(body, uniEntities, EXCEPTION_MESSAGE, (listBody, list) -> returnValueWithLinks(listBody, resourceMetadata, resourceProperties, list, @@ -322,41 +317,21 @@ private void implementNotPaged(ClassCreator classCreator, ResourceMetadata resou methodCreator.close(); } - public ResultHandle list(BytecodeCreator creator, ResourceMetadata resourceMetadata, ResultHandle resource, - ResultHandle page, ResultHandle sort, ResultHandle namedQuery, Map fieldValues) { + private ResultHandle pageCount(BytecodeCreator creator, ResourceMetadata resourceMetadata, ResultHandle resource, + ResultHandle page, ResultHandle namedQuery, Map fieldValues, Object returnType) { + AssignableResultHandle query = queryImplementor.getQuery(creator, namedQuery, fieldValues); + ResultHandle dataParams = queryImplementor.getDataParams(creator, fieldValues); - ResultHandle dataParams = creator.newInstance(ofConstructor(HashMap.class)); - ResultHandle queryList = creator.newInstance(ofConstructor(ArrayList.class)); - for (Map.Entry field : fieldValues.entrySet()) { - String fieldName = field.getKey(); - String paramName = fieldName.replace(".", "__"); - ResultHandle fieldValueFromQuery = field.getValue(); - BytecodeCreator fieldValueFromQueryIsSet = creator.ifNotNull(fieldValueFromQuery).trueBranch(); - fieldValueFromQueryIsSet.invokeInterfaceMethod(ofMethod(List.class, "add", boolean.class, Object.class), - queryList, fieldValueFromQueryIsSet.load(fieldName + "=:" + paramName)); - fieldValueFromQueryIsSet.invokeInterfaceMethod( - ofMethod(Map.class, "put", Object.class, Object.class, Object.class), - dataParams, fieldValueFromQueryIsSet.load(paramName), fieldValueFromQuery); - } + return creator.invokeVirtualMethod( + ofMethod(resourceMetadata.getResourceClass(), Constants.PAGE_COUNT_METHOD_PREFIX + RESOURCE_METHOD_NAME, + returnType, Page.class, String.class, Map.class), + resource, page, query, dataParams); + } - /** - * String query; - * if (namedQuery != null) { - * query = "#" + namedQuery; - * } else { - * query = String.join(" AND ", queryList); - * } - */ - AssignableResultHandle query = creator.createVariable(String.class); - BranchResult checkIfNamedQueryIsNull = creator.ifNull(namedQuery); - BytecodeCreator whenNamedQueryIsNull = checkIfNamedQueryIsNull.trueBranch(); - BytecodeCreator whenNamedQueryIsNotNull = checkIfNamedQueryIsNull.falseBranch(); - whenNamedQueryIsNotNull.assign(query, whenNamedQueryIsNotNull.invokeVirtualMethod( - ofMethod(String.class, "concat", String.class, String.class), - whenNamedQueryIsNotNull.load("#"), namedQuery)); - whenNamedQueryIsNull.assign(query, whenNamedQueryIsNull.invokeStaticMethod( - ofMethod(String.class, "join", String.class, CharSequence.class, Iterable.class), - creator.load(" AND "), queryList)); + public ResultHandle list(BytecodeCreator creator, ResourceMetadata resourceMetadata, ResultHandle resource, + ResultHandle page, ResultHandle sort, ResultHandle namedQuery, Map fieldValues) { + AssignableResultHandle query = queryImplementor.getQuery(creator, namedQuery, fieldValues); + ResultHandle dataParams = queryImplementor.getDataParams(creator, fieldValues); return creator.invokeVirtualMethod( ofMethod(resourceMetadata.getResourceClass(), "list", isNotReactivePanache() ? List.class : Uni.class, diff --git a/extensions/panache/rest-data-panache/deployment/src/main/java/io/quarkus/rest/data/panache/deployment/utils/PaginationImplementor.java b/extensions/panache/rest-data-panache/deployment/src/main/java/io/quarkus/rest/data/panache/deployment/utils/PaginationImplementor.java index 08723f99ebe59..e45a14e46f35b 100644 --- a/extensions/panache/rest-data-panache/deployment/src/main/java/io/quarkus/rest/data/panache/deployment/utils/PaginationImplementor.java +++ b/extensions/panache/rest-data-panache/deployment/src/main/java/io/quarkus/rest/data/panache/deployment/utils/PaginationImplementor.java @@ -6,6 +6,7 @@ import java.net.URI; import java.util.ArrayList; import java.util.List; +import java.util.Map; import jakarta.ws.rs.core.Link; import jakarta.ws.rs.core.UriBuilder; @@ -48,26 +49,27 @@ private ResultHandle getValidOrDefault(BytecodeCreator creator, ResultHandle val * Return an array with the links applicable for the provided page and page count. */ public ResultHandle getLinks(BytecodeCreator creator, ResultHandle uriInfo, ResultHandle page, - ResultHandle pageCount) { + ResultHandle pageCount, Map fieldValues, ResultHandle namedQuery) { ResultHandle links = creator.newInstance(ofConstructor(ArrayList.class, int.class), creator.load(4)); ResultHandle firstPage = creator.invokeVirtualMethod(ofMethod(Page.class, "first", Page.class), page); - ResultHandle firstPageLink = getLink(creator, uriInfo, firstPage, "first"); + ResultHandle firstPageLink = getLink(creator, uriInfo, firstPage, "first", fieldValues, namedQuery); creator.invokeInterfaceMethod(ofMethod(List.class, "add", boolean.class, Object.class), links, firstPageLink); ResultHandle lastPage = getLastPage(creator, page, pageCount); - ResultHandle lastPageLink = getLink(creator, uriInfo, lastPage, "last"); + ResultHandle lastPageLink = getLink(creator, uriInfo, lastPage, "last", fieldValues, namedQuery); creator.invokeInterfaceMethod(ofMethod(List.class, "add", boolean.class, Object.class), links, lastPageLink); BytecodeCreator previousPageCreator = isTheSamePage(creator, page, firstPage).falseBranch(); ResultHandle previousPage = previousPageCreator.invokeVirtualMethod(ofMethod(Page.class, "previous", Page.class), page); - ResultHandle previousPageLink = getLink(previousPageCreator, uriInfo, previousPage, "previous"); + ResultHandle previousPageLink = getLink(previousPageCreator, uriInfo, previousPage, "previous", fieldValues, + namedQuery); previousPageCreator.invokeInterfaceMethod( ofMethod(List.class, "add", boolean.class, Object.class), links, previousPageLink); BytecodeCreator nextPageCreator = isTheSamePage(creator, page, lastPage).falseBranch(); ResultHandle nextPage = nextPageCreator.invokeVirtualMethod(ofMethod(Page.class, "next", Page.class), page); - ResultHandle nextPageLink = getLink(nextPageCreator, uriInfo, nextPage, "next"); + ResultHandle nextPageLink = getLink(nextPageCreator, uriInfo, nextPage, "next", fieldValues, namedQuery); nextPageCreator.invokeInterfaceMethod(ofMethod(List.class, "add", boolean.class, Object.class), links, nextPageLink); ResultHandle linksCount = creator.invokeInterfaceMethod(ofMethod(List.class, "size", int.class), links); @@ -76,9 +78,11 @@ public ResultHandle getLinks(BytecodeCreator creator, ResultHandle uriInfo, Resu ofMethod(List.class, "toArray", Object[].class, Object[].class), links, linksArray); } - private ResultHandle getLink(BytecodeCreator creator, ResultHandle uriInfo, ResultHandle page, String rel) { + private ResultHandle getLink(BytecodeCreator creator, ResultHandle uriInfo, ResultHandle page, String rel, + Map fieldValues, ResultHandle namedQuery) { ResultHandle builder = creator.invokeStaticMethod( - ofMethod(Link.class, "fromUri", Link.Builder.class, URI.class), getPageUri(creator, uriInfo, page)); + ofMethod(Link.class, "fromUri", Link.Builder.class, URI.class), + getPageUri(creator, uriInfo, page, fieldValues, namedQuery)); creator.invokeInterfaceMethod(ofMethod(Link.Builder.class, "rel", Link.Builder.class, String.class), builder, creator.load(rel)); return creator.invokeInterfaceMethod(ofMethod(Link.Builder.class, "build", Link.class, Object[].class), @@ -92,9 +96,11 @@ private ResultHandle getLink(BytecodeCreator creator, ResultHandle uriInfo, Resu * @param creator a bytecode creator to be used for code generation * @param uriInfo a {@link UriInfo} to be used for the absolute path extraction * @param page a {@link Page} to be used for getting page number and size + * @param namedQuery a custom query * @return a page {@link URI} */ - private ResultHandle getPageUri(BytecodeCreator creator, ResultHandle uriInfo, ResultHandle page) { + private ResultHandle getPageUri(BytecodeCreator creator, ResultHandle uriInfo, ResultHandle page, + Map fieldValues, ResultHandle namedQuery) { ResultHandle uriBuilder = creator.invokeInterfaceMethod( ofMethod(UriInfo.class, "getAbsolutePathBuilder", UriBuilder.class), uriInfo); @@ -110,6 +116,19 @@ private ResultHandle getPageUri(BytecodeCreator creator, ResultHandle uriInfo, R ofMethod(UriBuilder.class, "queryParam", UriBuilder.class, String.class, Object[].class), uriBuilder, creator.load("size"), creator.marshalAsArray(Object.class, size)); + BytecodeCreator existNamedQuery = creator.ifNotNull(namedQuery).trueBranch(); + existNamedQuery.invokeVirtualMethod( + ofMethod(UriBuilder.class, "queryParam", UriBuilder.class, String.class, Object[].class), + uriBuilder, existNamedQuery.load("namedQuery"), existNamedQuery.marshalAsArray(Object.class, namedQuery)); + + for (Map.Entry field : fieldValues.entrySet()) { + BytecodeCreator existFieldValue = creator.ifNotNull(field.getValue()).trueBranch(); + existFieldValue.invokeVirtualMethod( + ofMethod(UriBuilder.class, "queryParam", UriBuilder.class, String.class, Object[].class), + uriBuilder, existFieldValue.load(field.getKey()), + existFieldValue.marshalAsArray(Object.class, field.getValue())); + } + return creator.invokeVirtualMethod( ofMethod(UriBuilder.class, "build", URI.class, Object[].class), uriBuilder, creator.newArray(Object.class, 0)); } diff --git a/extensions/panache/rest-data-panache/deployment/src/main/java/io/quarkus/rest/data/panache/deployment/utils/QueryImplementor.java b/extensions/panache/rest-data-panache/deployment/src/main/java/io/quarkus/rest/data/panache/deployment/utils/QueryImplementor.java new file mode 100644 index 0000000000000..28ad2fb05fa0a --- /dev/null +++ b/extensions/panache/rest-data-panache/deployment/src/main/java/io/quarkus/rest/data/panache/deployment/utils/QueryImplementor.java @@ -0,0 +1,78 @@ +package io.quarkus.rest.data.panache.deployment.utils; + +import static io.quarkus.gizmo.MethodDescriptor.ofConstructor; +import static io.quarkus.gizmo.MethodDescriptor.ofMethod; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import io.quarkus.gizmo.AssignableResultHandle; +import io.quarkus.gizmo.BranchResult; +import io.quarkus.gizmo.BytecodeCreator; +import io.quarkus.gizmo.ResultHandle; + +public final class QueryImplementor { + /** + * Returns the name of the query or if it is not defined, then it will return a query built by the search parameters. + * + *
+     * {@code
+     * String query;
+     * if (namedQuery != null) {
+     *     query = "#" + namedQuery;
+     * } else {
+     *     query = String.join(" AND ", queryList);
+     * }
+     * }
+     * 
+ * + * @param creator a bytecode creator to be used for code generation. + * @param namedQuery HQL query to list entities. + * @param fieldValues fields query params. + * @return query. + */ + public AssignableResultHandle getQuery(BytecodeCreator creator, ResultHandle namedQuery, + Map fieldValues) { + ResultHandle queryList = creator.newInstance(ofConstructor(ArrayList.class)); + + for (Map.Entry field : fieldValues.entrySet()) { + String fieldName = field.getKey(); + String paramName = fieldName.replace(".", "__"); + ResultHandle fieldValueFromQuery = field.getValue(); + BytecodeCreator fieldValueFromQueryIsSet = creator.ifNotNull(fieldValueFromQuery).trueBranch(); + fieldValueFromQueryIsSet.invokeInterfaceMethod(ofMethod(List.class, "add", boolean.class, Object.class), + queryList, fieldValueFromQueryIsSet.load(fieldName + "=:" + paramName)); + } + + AssignableResultHandle query = creator.createVariable(String.class); + BranchResult checkIfNamedQueryIsNull = creator.ifNull(namedQuery); + BytecodeCreator whenNamedQueryIsNull = checkIfNamedQueryIsNull.trueBranch(); + BytecodeCreator whenNamedQueryIsNotNull = checkIfNamedQueryIsNull.falseBranch(); + whenNamedQueryIsNotNull.assign(query, whenNamedQueryIsNotNull.invokeVirtualMethod( + ofMethod(String.class, "concat", String.class, String.class), + whenNamedQueryIsNotNull.load("#"), namedQuery)); + whenNamedQueryIsNull.assign(query, whenNamedQueryIsNull.invokeStaticMethod( + ofMethod(String.class, "join", String.class, CharSequence.class, Iterable.class), + creator.load(" AND "), queryList)); + + return query; + } + + public ResultHandle getDataParams(BytecodeCreator creator, Map fieldValues) { + ResultHandle dataParams = creator.newInstance(ofConstructor(HashMap.class)); + + for (Map.Entry field : fieldValues.entrySet()) { + String fieldName = field.getKey(); + String paramName = fieldName.replace(".", "__"); + ResultHandle fieldValueFromQuery = field.getValue(); + BytecodeCreator fieldValueFromQueryIsSet = creator.ifNotNull(fieldValueFromQuery).trueBranch(); + fieldValueFromQueryIsSet.invokeInterfaceMethod( + ofMethod(Map.class, "put", Object.class, Object.class, Object.class), + dataParams, fieldValueFromQueryIsSet.load(paramName), fieldValueFromQuery); + } + + return dataParams; + } +} diff --git a/extensions/spring-data-rest/deployment/src/main/java/io/quarkus/spring/data/rest/deployment/RepositoryMethodsImplementor.java b/extensions/spring-data-rest/deployment/src/main/java/io/quarkus/spring/data/rest/deployment/RepositoryMethodsImplementor.java index 22b936f891448..33a1f25fe1218 100644 --- a/extensions/spring-data-rest/deployment/src/main/java/io/quarkus/spring/data/rest/deployment/RepositoryMethodsImplementor.java +++ b/extensions/spring-data-rest/deployment/src/main/java/io/quarkus/spring/data/rest/deployment/RepositoryMethodsImplementor.java @@ -131,7 +131,7 @@ public void implementPagedList(ClassCreator classCreator, String repositoryInter //PagingAndSortingRepository Page findAll(Pageable pageable); public void implementListPageCount(ClassCreator classCreator, String repositoryInterfaceName) { MethodCreator methodCreator = classCreator.getMethodCreator(Constants.PAGE_COUNT_METHOD_PREFIX + "list", - int.class, Page.class); + int.class, Page.class, String.class, Map.class); if (entityClassHelper.isPagingAndSortingRepository(repositoryInterfaceName)) { ResultHandle page = methodCreator.getMethodParam(0); ResultHandle pageable = toPageable(methodCreator, page); From 1205d80b34943645ecbf67da52acaf4809d7da23 Mon Sep 17 00:00:00 2001 From: Guillaume Smet Date: Fri, 2 Aug 2024 09:40:01 +0200 Subject: [PATCH 03/17] Add one more level of TOC for Qute reference guide Typically, you cannot find User-defined tags in the TOC, which is a bit annoying. Companion PR: https://github.com/quarkusio/quarkusio.github.io/pull/2067 (cherry picked from commit deb17e24fedc21e0fe264eec96a85476ae8622fd) --- docs/src/main/asciidoc/qute-reference.adoc | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/src/main/asciidoc/qute-reference.adoc b/docs/src/main/asciidoc/qute-reference.adoc index f93422a0e1303..9eb8dd6cc228a 100644 --- a/docs/src/main/asciidoc/qute-reference.adoc +++ b/docs/src/main/asciidoc/qute-reference.adoc @@ -10,6 +10,7 @@ include::_attributes.adoc[] :numbered: :sectnums: :sectnumlevels: 4 +:toclevels: 3 :topics: templating,qute :extensions: io.quarkus:quarkus-qute,io.quarkus:quarkus-resteasy-qute,io.quarkus:quarkus-rest-qute From 515f2d3226651b7ed3c4d17681d0aab74cea1864 Mon Sep 17 00:00:00 2001 From: Martin Kouba Date: Fri, 2 Aug 2024 08:54:17 +0200 Subject: [PATCH 04/17] WebSockets Next: CloseReason - fix NPE if connection terminated abruptly - fix invocation of OnClose callback with a CloseReason param - resolves #42271 (cherry picked from commit 983b8bfc6861c8c6a2b07db0d4624110b435d845) --- .../main/java/io/quarkus/websockets/next/CloseReason.java | 5 +++++ .../websockets/next/runtime/WebSocketConnectionBase.java | 7 ++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/extensions/websockets-next/runtime/src/main/java/io/quarkus/websockets/next/CloseReason.java b/extensions/websockets-next/runtime/src/main/java/io/quarkus/websockets/next/CloseReason.java index 108c2d150b55b..009155eb67e41 100644 --- a/extensions/websockets-next/runtime/src/main/java/io/quarkus/websockets/next/CloseReason.java +++ b/extensions/websockets-next/runtime/src/main/java/io/quarkus/websockets/next/CloseReason.java @@ -50,4 +50,9 @@ public String getMessage() { return message; } + @Override + public String toString() { + return "CloseReason [code=" + code + ", " + (message != null ? "message=" + message : "") + "]"; + } + } diff --git a/extensions/websockets-next/runtime/src/main/java/io/quarkus/websockets/next/runtime/WebSocketConnectionBase.java b/extensions/websockets-next/runtime/src/main/java/io/quarkus/websockets/next/runtime/WebSocketConnectionBase.java index 3b5694e9ac8c6..4febc7792d813 100644 --- a/extensions/websockets-next/runtime/src/main/java/io/quarkus/websockets/next/runtime/WebSocketConnectionBase.java +++ b/extensions/websockets-next/runtime/src/main/java/io/quarkus/websockets/next/runtime/WebSocketConnectionBase.java @@ -131,7 +131,12 @@ public BroadcastSender broadcast() { public CloseReason closeReason() { WebSocketBase ws = webSocket(); if (ws.isClosed()) { - return new CloseReason(ws.closeStatusCode(), ws.closeReason()); + Short code = ws.closeStatusCode(); + if (code == null) { + // This could happen if the connection is terminated abruptly + return CloseReason.INTERNAL_SERVER_ERROR; + } + return new CloseReason(code, ws.closeReason()); } return null; } From 13bd9a31d3dc5a95b06593ddb87c251d8896ab40 Mon Sep 17 00:00:00 2001 From: xstefank Date: Fri, 2 Aug 2024 10:48:25 +0200 Subject: [PATCH 05/17] Fix typo in JBang doc (cherry picked from commit f0e136a6ca5f241514de5ffb4e950b83aa588b1a) --- docs/src/main/asciidoc/scripting.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/main/asciidoc/scripting.adoc b/docs/src/main/asciidoc/scripting.adoc index c2ea4bddbee9c..6f0fe640c3c14 100644 --- a/docs/src/main/asciidoc/scripting.adoc +++ b/docs/src/main/asciidoc/scripting.adoc @@ -112,7 +112,7 @@ The next lines [source,java] ---- -// //DEPS +//DEPS ---- illustrate how you add dependencies to this script. This is a feature of JBang. From 753ad3c5487a2865582eb5cb396b9ebcde41c570 Mon Sep 17 00:00:00 2001 From: Laurent Broudoux Date: Fri, 2 Aug 2024 10:41:29 +0200 Subject: [PATCH 06/17] feat: Allow funer tuning of shared network usage by Keycloak DevServices Signed-off-by: Laurent Broudoux (cherry picked from commit e4d746e212830049825dc9c33bc70ff1c34995c7) --- .../devservices/keycloak/KeycloakDevServicesProcessor.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/keycloak/KeycloakDevServicesProcessor.java b/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/keycloak/KeycloakDevServicesProcessor.java index fbf7511f0bfae..cb54e61efe09d 100644 --- a/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/keycloak/KeycloakDevServicesProcessor.java +++ b/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/keycloak/KeycloakDevServicesProcessor.java @@ -195,8 +195,10 @@ public DevServicesResultBuildItem startKeycloakContainer( try { List errors = new ArrayList<>(); + boolean useSharedNetwork = DevServicesSharedNetworkBuildItem.isSharedNetworkRequired(devServicesConfig, + devServicesSharedNetworkBuildItem); RunningDevService newDevService = startContainer(dockerStatusBuildItem, keycloakBuildItemBuildProducer, - !devServicesSharedNetworkBuildItem.isEmpty(), + useSharedNetwork, devServicesConfig.timeout, errors); if (newDevService == null) { From 466b0a44cf79414cf8b26156404f128f791d68a4 Mon Sep 17 00:00:00 2001 From: vsevel Date: Fri, 2 Aug 2024 11:26:27 +0200 Subject: [PATCH 07/17] Missing = in system property additionalUpdateRecipes for quarkus update maven runner (cherry picked from commit cf28f41e8fe342af9f7a5077856cd4d69b9bfeb9) --- .../cli/src/main/java/io/quarkus/cli/build/MavenRunner.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devtools/cli/src/main/java/io/quarkus/cli/build/MavenRunner.java b/devtools/cli/src/main/java/io/quarkus/cli/build/MavenRunner.java index 948feb9f3db81..94598c02ce826 100644 --- a/devtools/cli/src/main/java/io/quarkus/cli/build/MavenRunner.java +++ b/devtools/cli/src/main/java/io/quarkus/cli/build/MavenRunner.java @@ -177,7 +177,7 @@ public Integer updateProject(TargetQuarkusVersionGroup targetQuarkusVersion, Rew args.add("-DquarkusUpdateRecipes=" + rewrite.quarkusUpdateRecipes); } if (rewrite.additionalUpdateRecipes != null) { - args.add("-DadditionalUpdateRecipes" + rewrite.additionalUpdateRecipes); + args.add("-DadditionalUpdateRecipes=" + rewrite.additionalUpdateRecipes); } if (rewrite.dryRun) { args.add("-DrewriteDryRun"); From c1dd65880922a3ad9b917c83d6afd04970f8e97c Mon Sep 17 00:00:00 2001 From: Diego Pedregal Date: Tue, 30 Jul 2024 11:07:38 +0200 Subject: [PATCH 08/17] Fix group overriding with machine username (cherry picked from commit 791ab5e396c2c6fefa05b9b276ecfeec984a0f7e) --- .../cli/src/main/java/io/quarkus/cli/image/ImageOptions.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devtools/cli/src/main/java/io/quarkus/cli/image/ImageOptions.java b/devtools/cli/src/main/java/io/quarkus/cli/image/ImageOptions.java index c5597640091ce..a2a7c8a372627 100644 --- a/devtools/cli/src/main/java/io/quarkus/cli/image/ImageOptions.java +++ b/devtools/cli/src/main/java/io/quarkus/cli/image/ImageOptions.java @@ -9,7 +9,7 @@ public class ImageOptions { @CommandLine.Option(order = 3, names = { "--group" }, description = "The group part of the container image. Defaults to the ${user.name}.") - public Optional group = Optional.of(System.getProperty("user.name")); + public Optional group = Optional.empty(); @CommandLine.Option(order = 4, names = { "--name" }, description = "The name part of the container image. Defaults to the ${project.artifactId}.") From e89bc38654b798be09fd22d22cd6e823956c4250 Mon Sep 17 00:00:00 2001 From: xstefank Date: Fri, 2 Aug 2024 12:22:36 +0200 Subject: [PATCH 09/17] Fix a race condition in ReactiveDatasourceHealthCheck data field population (cherry picked from commit 9d9534b2cc06f4df35ddae3768358a4e8b0ef72f) --- .../ReactiveDatasourceHealthCheck.java | 3 +- .../DataSourceHealthCheckPayloadTest.java | 28 +++++++++++++++++++ .../DataSourceHealthCheckPayloadTest.java | 28 +++++++++++++++++++ .../DataSourceHealthCheckPayloadTest.java | 28 +++++++++++++++++++ .../DataSourceHealthCheckPayloadTest.java | 28 +++++++++++++++++++ 5 files changed, 114 insertions(+), 1 deletion(-) create mode 100644 extensions/reactive-mssql-client/deployment/src/test/java/io/quarkus/reactive/mssql/client/DataSourceHealthCheckPayloadTest.java create mode 100644 extensions/reactive-mysql-client/deployment/src/test/java/io/quarkus/reactive/mysql/client/DataSourceHealthCheckPayloadTest.java create mode 100644 extensions/reactive-oracle-client/deployment/src/test/java/io/quarkus/reactive/oracle/client/DataSourceHealthCheckPayloadTest.java create mode 100644 extensions/reactive-pg-client/deployment/src/test/java/io/quarkus/reactive/pg/client/DataSourceHealthCheckPayloadTest.java diff --git a/extensions/reactive-datasource/runtime/src/main/java/io/quarkus/reactive/datasource/runtime/ReactiveDatasourceHealthCheck.java b/extensions/reactive-datasource/runtime/src/main/java/io/quarkus/reactive/datasource/runtime/ReactiveDatasourceHealthCheck.java index b0d804266c96b..840dec97bd7e7 100644 --- a/extensions/reactive-datasource/runtime/src/main/java/io/quarkus/reactive/datasource/runtime/ReactiveDatasourceHealthCheck.java +++ b/extensions/reactive-datasource/runtime/src/main/java/io/quarkus/reactive/datasource/runtime/ReactiveDatasourceHealthCheck.java @@ -76,7 +76,6 @@ public HealthCheckResponse call() { //20 seconds is rather high, but using just 10 is often not enough on slow CI //systems, especially if the connections have to be established for the first time. databaseConnectionAttempt.get(20, TimeUnit.SECONDS); - builder.withData(dataSourceName, "UP"); } catch (RuntimeException | ExecutionException exception) { operationsError(dataSourceName, exception); builder.down(); @@ -105,6 +104,8 @@ private void checkFailure(AsyncResult> ar, HealthCheckResponseBuilde operationsError(dataSourceName, ar.cause()); builder.down(); builder.withData(dataSourceName, "down - connection failed: " + ar.cause().getMessage()); + } else { + builder.withData(dataSourceName, "UP"); } } diff --git a/extensions/reactive-mssql-client/deployment/src/test/java/io/quarkus/reactive/mssql/client/DataSourceHealthCheckPayloadTest.java b/extensions/reactive-mssql-client/deployment/src/test/java/io/quarkus/reactive/mssql/client/DataSourceHealthCheckPayloadTest.java new file mode 100644 index 0000000000000..11f13aafbb78b --- /dev/null +++ b/extensions/reactive-mssql-client/deployment/src/test/java/io/quarkus/reactive/mssql/client/DataSourceHealthCheckPayloadTest.java @@ -0,0 +1,28 @@ +package io.quarkus.reactive.mssql.client; + +import org.hamcrest.CoreMatchers; +import org.hamcrest.Matchers; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; +import io.restassured.RestAssured; + +public class DataSourceHealthCheckPayloadTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .withEmptyApplication() + .overrideConfigKey("quarkus.datasource.health.enabled", "true") + .overrideConfigKey("quarkus.devservices.enabled", "false"); + + @Test + public void testDataSourceHealthCheckPayload() { + RestAssured.when().get("/q/health/ready") + .then() + .body("status", CoreMatchers.equalTo("DOWN")) + .body("checks.data", CoreMatchers + .hasItem(Matchers.hasValue(CoreMatchers.containsString("down - connection failed")))); + } + +} diff --git a/extensions/reactive-mysql-client/deployment/src/test/java/io/quarkus/reactive/mysql/client/DataSourceHealthCheckPayloadTest.java b/extensions/reactive-mysql-client/deployment/src/test/java/io/quarkus/reactive/mysql/client/DataSourceHealthCheckPayloadTest.java new file mode 100644 index 0000000000000..c219c54b0afbd --- /dev/null +++ b/extensions/reactive-mysql-client/deployment/src/test/java/io/quarkus/reactive/mysql/client/DataSourceHealthCheckPayloadTest.java @@ -0,0 +1,28 @@ +package io.quarkus.reactive.mysql.client; + +import org.hamcrest.CoreMatchers; +import org.hamcrest.Matchers; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; +import io.restassured.RestAssured; + +public class DataSourceHealthCheckPayloadTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .withEmptyApplication() + .overrideConfigKey("quarkus.datasource.health.enabled", "true") + .overrideConfigKey("quarkus.devservices.enabled", "false"); + + @Test + public void testDataSourceHealthCheckPayload() { + RestAssured.when().get("/q/health/ready") + .then() + .body("status", CoreMatchers.equalTo("DOWN")) + .body("checks.data", CoreMatchers + .hasItem(Matchers.hasValue(CoreMatchers.containsString("down - connection failed")))); + } + +} diff --git a/extensions/reactive-oracle-client/deployment/src/test/java/io/quarkus/reactive/oracle/client/DataSourceHealthCheckPayloadTest.java b/extensions/reactive-oracle-client/deployment/src/test/java/io/quarkus/reactive/oracle/client/DataSourceHealthCheckPayloadTest.java new file mode 100644 index 0000000000000..22daf2732285b --- /dev/null +++ b/extensions/reactive-oracle-client/deployment/src/test/java/io/quarkus/reactive/oracle/client/DataSourceHealthCheckPayloadTest.java @@ -0,0 +1,28 @@ +package io.quarkus.reactive.oracle.client; + +import org.hamcrest.CoreMatchers; +import org.hamcrest.Matchers; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; +import io.restassured.RestAssured; + +public class DataSourceHealthCheckPayloadTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .withEmptyApplication() + .overrideConfigKey("quarkus.datasource.health.enabled", "true") + .overrideConfigKey("quarkus.devservices.enabled", "false"); + + @Test + public void testDataSourceHealthCheckPayload() { + RestAssured.when().get("/q/health/ready") + .then() + .body("status", CoreMatchers.equalTo("DOWN")) + .body("checks.data", CoreMatchers + .hasItem(Matchers.hasValue(CoreMatchers.containsString("down - connection failed")))); + } + +} diff --git a/extensions/reactive-pg-client/deployment/src/test/java/io/quarkus/reactive/pg/client/DataSourceHealthCheckPayloadTest.java b/extensions/reactive-pg-client/deployment/src/test/java/io/quarkus/reactive/pg/client/DataSourceHealthCheckPayloadTest.java new file mode 100644 index 0000000000000..77e65102d0634 --- /dev/null +++ b/extensions/reactive-pg-client/deployment/src/test/java/io/quarkus/reactive/pg/client/DataSourceHealthCheckPayloadTest.java @@ -0,0 +1,28 @@ +package io.quarkus.reactive.pg.client; + +import org.hamcrest.CoreMatchers; +import org.hamcrest.Matchers; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; +import io.restassured.RestAssured; + +public class DataSourceHealthCheckPayloadTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .withEmptyApplication() + .overrideConfigKey("quarkus.datasource.health.enabled", "true") + .overrideConfigKey("quarkus.devservices.enabled", "false"); + + @Test + public void testDataSourceHealthCheckPayload() { + RestAssured.when().get("/q/health/ready") + .then() + .body("status", CoreMatchers.equalTo("DOWN")) + .body("checks.data", CoreMatchers + .hasItem(Matchers.hasValue(CoreMatchers.containsString("down - connection failed")))); + } + +} From b0c86acf4513d6b86ecbb389d56e03c8f33fa04e Mon Sep 17 00:00:00 2001 From: Guillaume Smet Date: Mon, 5 Aug 2024 16:35:57 +0200 Subject: [PATCH 10/17] Actually upgrade Vert.x to 4.5.9 in the BOM This is a followup of #41955 where updating the BOM was forgotten. (cherry picked from commit 35db8c41447b3aa333e3b88035420a7c769f7e5b) --- bom/application/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bom/application/pom.xml b/bom/application/pom.xml index 7cf2c464062dc..1591f4d09ff01 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -113,7 +113,7 @@ 2.5.0.Final 2.1.4.SP1 3.6.1.Final - 4.5.8 + 4.5.9 4.5.14 4.4.16 4.1.5 From ebcc9c707aa3e83364080ca713b7847bb7598746 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 5 Aug 2024 21:29:56 +0000 Subject: [PATCH 11/17] Bump org.eclipse:yasson from 3.0.3 to 3.0.4 Bumps [org.eclipse:yasson](https://github.com/eclipse-ee4j/yasson) from 3.0.3 to 3.0.4. - [Release notes](https://github.com/eclipse-ee4j/yasson/releases) - [Commits](https://github.com/eclipse-ee4j/yasson/compare/3.0.3...3.0.4) --- updated-dependencies: - dependency-name: org.eclipse:yasson dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] (cherry picked from commit 48a6ad0e5a71329ff710f86fc11fd876b2676e43) --- bom/application/pom.xml | 2 +- independent-projects/resteasy-reactive/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bom/application/pom.xml b/bom/application/pom.xml index 1591f4d09ff01..e0e6a6256b39d 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -160,7 +160,7 @@ 4.2.1 3.0.6.Final 10.15.2 - 3.0.3 + 3.0.4 4.27.0 4.24.0 diff --git a/independent-projects/resteasy-reactive/pom.xml b/independent-projects/resteasy-reactive/pom.xml index 6beec95db70b0..c305e3fd84091 100644 --- a/independent-projects/resteasy-reactive/pom.xml +++ b/independent-projects/resteasy-reactive/pom.xml @@ -64,7 +64,7 @@ 2.17.2 2.6.0 3.0.2 - 3.0.3 + 3.0.4 3.0.1 4.2.1 3.13.2 From 2109207e8dbfa2012332c0534931b4acab3ea8e6 Mon Sep 17 00:00:00 2001 From: Stuart Douglas Date: Tue, 6 Aug 2024 16:49:35 +1000 Subject: [PATCH 12/17] Add ability to always require a socket I have a use case the combines both virtual dispatch and standard HTTP, this lets extensions support both. (cherry picked from commit 6750fe6d43b5059838e13cd1826ea1a3e4200516) --- .../http/deployment/RequireSocketHttpBuildItem.java | 13 +++++++++++++ .../vertx/http/deployment/VertxHttpProcessor.java | 6 ++++-- 2 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/RequireSocketHttpBuildItem.java diff --git a/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/RequireSocketHttpBuildItem.java b/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/RequireSocketHttpBuildItem.java new file mode 100644 index 0000000000000..18f4debbea48d --- /dev/null +++ b/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/RequireSocketHttpBuildItem.java @@ -0,0 +1,13 @@ +package io.quarkus.vertx.http.deployment; + +import io.quarkus.builder.item.SimpleBuildItem; + +/** + * Marker class that can be used to force the socket to open even when using virtual HTTP. + * + * There are some use cases that may want to handle both real and virtual HTTP requests, such as mapping incoming + * gRPC requests onto JAX-RS handlers. + */ +public final class RequireSocketHttpBuildItem extends SimpleBuildItem { + public static final RequireSocketHttpBuildItem MARKER = new RequireSocketHttpBuildItem(); +} diff --git a/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/VertxHttpProcessor.java b/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/VertxHttpProcessor.java index 495e331d6257a..d66390edf7334 100644 --- a/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/VertxHttpProcessor.java +++ b/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/VertxHttpProcessor.java @@ -420,6 +420,7 @@ void openSocket(ApplicationStartBuildItem start, BuildProducer reflectiveClass, HttpBuildTimeConfig httpBuildTimeConfig, Optional requireVirtual, + Optional requireSocket, EventLoopCountBuildItem eventLoopCount, List websocketSubProtocols, Capabilities capabilities, @@ -430,8 +431,9 @@ void openSocket(ApplicationStartBuildItem start, .produce(ReflectiveClassBuildItem.builder(VirtualServerChannel.class) .build()); } - boolean startSocket = (!startVirtual || launchMode.getLaunchMode() != LaunchMode.NORMAL) - && (requireVirtual.isEmpty() || !requireVirtual.get().isAlwaysVirtual()); + boolean startSocket = requireSocket.isPresent() || + ((!startVirtual || launchMode.getLaunchMode() != LaunchMode.NORMAL) + && (requireVirtual.isEmpty() || !requireVirtual.get().isAlwaysVirtual())); recorder.startServer(vertx.getVertx(), shutdown, launchMode.getLaunchMode(), startVirtual, startSocket, eventLoopCount.getEventLoopCount(), From d26ad3fc30d244730e06cf2a5bf576db2c46aec4 Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Tue, 6 Aug 2024 14:11:24 +0300 Subject: [PATCH 13/17] Fix ClassLoader leak in KeycloakDevServicesProcessor Fixes: #42303 (cherry picked from commit d30d070b1132a2975bb1eac327f13e7445c0670b) --- .../keycloak/KeycloakDevServicesProcessor.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/keycloak/KeycloakDevServicesProcessor.java b/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/keycloak/KeycloakDevServicesProcessor.java index cb54e61efe09d..9086c453f4e27 100644 --- a/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/keycloak/KeycloakDevServicesProcessor.java +++ b/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/keycloak/KeycloakDevServicesProcessor.java @@ -189,9 +189,6 @@ public DevServicesResultBuildItem startKeycloakContainer( StartupLogCompressor compressor = new StartupLogCompressor( (launchMode.isTest() ? "(test) " : "") + "Keycloak Dev Services Starting:", consoleInstalledBuildItem, loggingSetupBuildItem); - if (vertxInstance == null) { - vertxInstance = Vertx.vertx(); - } try { List errors = new ArrayList<>(); @@ -281,6 +278,12 @@ private Map prepareConfiguration( List realmNames = new LinkedList<>(); + // this needs to be only if we actually start the dev-service as it adds a shutdown hook + // whose TCCL is the Augmentation CL, which if not removed, causes a massive memory leaks + if (vertxInstance == null) { + vertxInstance = Vertx.vertx(); + } + WebClient client = OidcDevServicesUtils.createWebClient(vertxInstance); try { String adminToken = getAdminToken(client, clientAuthServerBaseUrl); From b00af78a3b07e2d6e26ae5f40136d91aa661e9aa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Jul 2024 21:35:38 +0000 Subject: [PATCH 14/17] Bump org.mvnpm.at.mvnpm:vaadin-webcomponents from 24.4.2 to 24.4.4 Bumps [org.mvnpm.at.mvnpm:vaadin-webcomponents](https://github.com/vaadin/web-components) from 24.4.2 to 24.4.4. - [Release notes](https://github.com/vaadin/web-components/releases) - [Commits](https://github.com/vaadin/web-components/compare/v24.4.2...v24.4.4) --- updated-dependencies: - dependency-name: org.mvnpm.at.mvnpm:vaadin-webcomponents dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] (cherry picked from commit 6562c19b0c633d562d15816c0b7b2fd4fe7d9eae) --- bom/dev-ui/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bom/dev-ui/pom.xml b/bom/dev-ui/pom.xml index 4129bc25552c7..b84394d0aa67b 100644 --- a/bom/dev-ui/pom.xml +++ b/bom/dev-ui/pom.xml @@ -13,7 +13,7 @@ Dependency management for dev-ui. Importable by third party extension developers. - 24.4.2 + 24.4.4 3.1.4 4.0.6 3.1.4 From daf0ff3bf7efde26cfc5033aeab13ac4a14a50fe Mon Sep 17 00:00:00 2001 From: Phillip Kruger Date: Tue, 6 Aug 2024 20:15:24 +1000 Subject: [PATCH 15/17] Fix Dev UI Theme switch Signed-off-by: Phillip Kruger (cherry picked from commit 7d1b7ebf2f7a96b3e7048f823d8bb67f113dfa64) --- bom/dev-ui/pom.xml | 2 +- .../main/resources/dev-ui/qwc/qwc-header.js | 118 +----------------- .../resources/dev-ui/qwc/qwc-theme-switch.js | 98 +++++++++++++++ 3 files changed, 103 insertions(+), 115 deletions(-) create mode 100644 extensions/vertx-http/dev-ui-resources/src/main/resources/dev-ui/qwc/qwc-theme-switch.js diff --git a/bom/dev-ui/pom.xml b/bom/dev-ui/pom.xml index b84394d0aa67b..343d595627c0b 100644 --- a/bom/dev-ui/pom.xml +++ b/bom/dev-ui/pom.xml @@ -13,7 +13,7 @@ Dependency management for dev-ui. Importable by third party extension developers. - 24.4.4 + 24.4.5 3.1.4 4.0.6 3.1.4 diff --git a/extensions/vertx-http/dev-ui-resources/src/main/resources/dev-ui/qwc/qwc-header.js b/extensions/vertx-http/dev-ui-resources/src/main/resources/dev-ui/qwc/qwc-header.js index b46e5f26a74d6..20805111c7ea1 100644 --- a/extensions/vertx-http/dev-ui-resources/src/main/resources/dev-ui/qwc/qwc-header.js +++ b/extensions/vertx-http/dev-ui-resources/src/main/resources/dev-ui/qwc/qwc-header.js @@ -1,22 +1,18 @@ import { LitElement, html, css } from 'lit'; import { RouterController } from 'router-controller'; -import { StorageController } from 'storage-controller'; import { notifier } from 'notifier'; import { observeState } from 'lit-element-state'; import { themeState } from 'theme-state'; import { devuiState } from 'devui-state'; -import '@vaadin/menu-bar'; import '@vaadin/tabs'; -import '@vaadin/button'; import 'qwc/qwc-extension-link.js'; - +import './qwc-theme-switch.js'; /** * This component represent the Dev UI Header */ export class QwcHeader extends observeState(LitElement) { routerController = new RouterController(this); - storageControl = new StorageController(this); static styles = css` @@ -31,7 +27,7 @@ export class QwcHeader extends observeState(LitElement) { display: flex; justify-content: space-around; align-items: center; - padding-right: 60px; + padding-right: 10px; } .logo-title { @@ -88,13 +84,6 @@ export class QwcHeader extends observeState(LitElement) { align-items: center; } - .themeDropdown { - position: absolute; - right: 0px; - top: 10px; - z-index: 3; - } - .hidden { display:none; } @@ -103,10 +92,7 @@ export class QwcHeader extends observeState(LitElement) { static properties = { _title: {state: true}, _subTitle: {state: true}, - _rightSideNav: {state: true}, - _selectedTheme: {state: true}, - _themeOptions: {state: true}, - _desktopTheme: {state: true} + _rightSideNav: {state: true} }; constructor() { @@ -115,10 +101,6 @@ export class QwcHeader extends observeState(LitElement) { this._subTitle = null; this._rightSideNav = ""; - this._createThemeItems(); - this._restoreThemePreference(); - this._createThemeOptions(); - window.addEventListener('vaadin-router-location-changed', (event) => { this._updateHeader(event); }); @@ -126,34 +108,6 @@ export class QwcHeader extends observeState(LitElement) { connectedCallback() { super.connectedCallback(); - // Get desktop theme setting - this._desktopTheme = "dark"; - if(window.matchMedia){ - if(window.matchMedia('(prefers-color-scheme: light)').matches){ - this._desktopTheme = "light"; - } - - // Change theme setting when OS theme change - window.matchMedia('(prefers-color-scheme: light)').addEventListener('change', e => { - if(e.matches){ - this._desktopTheme = "light"; - }else{ - this._desktopTheme = "dark"; - } - this._changeToSelectedTheme(); - }); - } - - this._changeToSelectedTheme(); - } - - _restoreThemePreference() { - const storedValue = this.storageControl.get("theme-preference"); - if(storedValue){ - this._selectedTheme = storedValue; - }else { - this._selectedTheme = "desktop"; - } } render() { @@ -197,71 +151,7 @@ export class QwcHeader extends observeState(LitElement) { } _renderThemeOptions(){ - return html` - `; - } - - _changeThemeOption(e){ - this._selectedTheme = e.detail.value.name; - this._createThemeOptions(); - this._changeToSelectedTheme(); - this.storageControl.set('theme-preference', this._selectedTheme); - } - - _changeToSelectedTheme(){ - if(this._selectedTheme === "desktop"){ - themeState.changeTo(this._desktopTheme); - }else { - themeState.changeTo(this._selectedTheme); - } - } - - _createThemeOptions(){ - - let selectedComponent = this._desktopThemeItem; - if(this._selectedTheme === "dark"){ - selectedComponent = this._darkThemeItem; - }else if(this._selectedTheme === "light"){ - selectedComponent = this._lightThemeItem; - } - - this._themeOptions = [ - { - component: selectedComponent, - children: [ - { - component: this._darkThemeItem, - name: "dark" - }, - { - component: this._lightThemeItem, - name: "light" - }, - { - component: this._desktopThemeItem, - name: "desktop" - } - ] - } - - ]; - } - - _createThemeItems() { - this._darkThemeItem = this._createThemeItem("moon", "dark"); - this._lightThemeItem = this._createThemeItem("sun", "light"); - this._desktopThemeItem = this._createThemeItem("desktop", "desktop"); - } - - _createThemeItem(iconName, ariaLabel) { - const item = document.createElement('vaadin-context-menu-item'); - const icon = document.createElement('vaadin-icon'); - item.setAttribute('aria-label', ariaLabel); - icon.setAttribute('icon', `font-awesome-solid:${iconName}`); - item.appendChild(icon); - return item; + return html``; } _updateHeader(event){ diff --git a/extensions/vertx-http/dev-ui-resources/src/main/resources/dev-ui/qwc/qwc-theme-switch.js b/extensions/vertx-http/dev-ui-resources/src/main/resources/dev-ui/qwc/qwc-theme-switch.js new file mode 100644 index 0000000000000..8acb1fde66334 --- /dev/null +++ b/extensions/vertx-http/dev-ui-resources/src/main/resources/dev-ui/qwc/qwc-theme-switch.js @@ -0,0 +1,98 @@ +import { LitElement, html, css } from 'lit'; +import { themeState } from 'theme-state'; +import { StorageController } from 'storage-controller'; +import '@vaadin/button'; + +/** + * Basic theme switch + */ +export class QwcThemeSwitch extends LitElement { + storageControl = new StorageController(this); + + themes = [ + { id: 0, name: 'Desktop', icon: 'font-awesome-solid:desktop' }, + { id: 1, name: 'Light', icon: 'font-awesome-solid:sun' }, + { id: 2, name: 'Dark', icon: 'font-awesome-solid:moon' } + ]; + + static styles = css` + .themeButton { + padding-left: 10px; + } + .button { + --vaadin-button-background: var(--lumo-base-color); + } + `; + + static properties = { + _selectedThemeIndex: {state: true}, + }; + + constructor() { + super(); + this._restoreThemePreference(); + } + + connectedCallback() { + super.connectedCallback(); + this._desktopTheme = "dark"; // default + if(window.matchMedia){ + if(window.matchMedia('(prefers-color-scheme: light)').matches){ + this._desktopTheme = "light"; + } + + // Change theme setting when OS theme change + window.matchMedia('(prefers-color-scheme: light)').addEventListener('change', e => { + if(e.matches){ + this._desktopTheme = "light"; + }else{ + this._desktopTheme = "dark"; + } + if(this._selectedThemeIndex===0){ + this._changeToSelectedThemeIndex(); + } + }); + } + + this._changeToSelectedThemeIndex(); + } + + render() { + let theme = this.themes[this._selectedThemeIndex]; + + return html`
+ + + +
`; + } + + _nextTheme(e){ + this._selectedThemeIndex = (this._selectedThemeIndex + 1) % this.themes.length; + this._changeToSelectedThemeIndex(); + } + + _changeToSelectedThemeIndex(){ + let theme = this.themes[this._selectedThemeIndex]; + this.storageControl.set('theme-preference', theme.id); + + if(theme.id === 0){ // Desktop + themeState.changeTo(this._desktopTheme); + }else { + themeState.changeTo(theme.name.toLowerCase()); + } + + } + + _restoreThemePreference() { + const storedValue = this.storageControl.get("theme-preference"); + if(storedValue){ + this._selectedThemeIndex = storedValue; + } else { + this._selectedThemeIndex = 0; + } + } + + +} +customElements.define('qwc-theme-switch', QwcThemeSwitch); \ No newline at end of file From 9f9b3a975dc4ca132d470669d8402437364ade09 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 24 Jul 2024 21:09:36 +0000 Subject: [PATCH 16/17] Bump io.strimzi:strimzi-test-container from 0.106.0 to 0.107.0 Bumps [io.strimzi:strimzi-test-container](https://github.com/strimzi/test-container) from 0.106.0 to 0.107.0. - [Release notes](https://github.com/strimzi/test-container/releases) - [Commits](https://github.com/strimzi/test-container/compare/0.106.0...0.107.0) --- updated-dependencies: - dependency-name: io.strimzi:strimzi-test-container dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] (cherry picked from commit d76e10c4c87cffbf4bee8fd7e33669e55abf40e8) --- bom/application/pom.xml | 2 +- bom/test/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bom/application/pom.xml b/bom/application/pom.xml index e0e6a6256b39d..3535cfab2714e 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -143,7 +143,7 @@ 3.7.1 1.8.0 1.1.10.5 - 0.106.0 + 0.107.0 2.13.14 1.2.3 diff --git a/bom/test/pom.xml b/bom/test/pom.xml index c44c362e21ddb..a5ca7acc8bfa8 100644 --- a/bom/test/pom.xml +++ b/bom/test/pom.xml @@ -20,7 +20,7 @@ 2.3.1 1.3.8 - 0.106.0 + 0.107.0 1.0.0-alpha
From fd038255ed5e977293af5db74aa90c69ac5382b3 Mon Sep 17 00:00:00 2001 From: Peter Palaga Date: Tue, 6 Aug 2024 12:22:34 +0200 Subject: [PATCH 17/17] Manage mutiny-zero to make life of downstream Camel easier (cherry picked from commit c0eb627bd5995bce7c5d5d1d7df63b19bc31b40f) --- bom/application/pom.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/bom/application/pom.xml b/bom/application/pom.xml index 3535cfab2714e..f6a01ef63fe40 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -5743,6 +5743,11 @@ + + io.smallrye.reactive + mutiny-zero + ${mutiny-zero.version} + io.smallrye.reactive mutiny-zero-flow-adapters