From c4cb6bcc8d1a99702747ca447078216ceeefa806 Mon Sep 17 00:00:00 2001 From: Jose Date: Wed, 5 Jul 2023 11:42:27 +0200 Subject: [PATCH] Fix user methods requiring a session in Panache REST Data with Reactive These changes add the `@WithSessionOnDemand` annotation at class level when using Panache REST Data with Hibernate Reactive. This annotation makes user methods that return an Uni class to work. About tests, I've covered the following scenarios: - user GET method that returns an Uni - user POST method that returns an Uni (and requires a transaction) - injecting the generated resource will also work Fix https://github.com/quarkusio/quarkus/issues/34432 --- .../deployment/ResourceImplementor.java | 8 ++----- .../AbstractInjectResourcesMethodTest.java | 10 ++++++++ .../entity/CollectionsResource.java | 24 +++++++++++++++++++ .../deployment/entity/InjectionResource.java | 11 +++++++++ .../PanacheEntityResourceGetMethodTest.java | 13 ++++++++++ .../PanacheEntityResourcePostMethodTest.java | 13 ++++++++++ .../repository/CollectionsResource.java | 22 +++++++++++++++++ ...anacheRepositoryResourceGetMethodTest.java | 13 ++++++++++ ...nacheRepositoryResourcePostMethodTest.java | 13 ++++++++++ .../deployment/JaxRsResourceImplementor.java | 4 ++++ 10 files changed, 125 insertions(+), 6 deletions(-) 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 6fc0fb62e719de..2dcc24a7a3a41e 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 @@ -20,7 +20,7 @@ import io.quarkus.gizmo.MethodCreator; import io.quarkus.gizmo.MethodDescriptor; import io.quarkus.gizmo.ResultHandle; -import io.quarkus.hibernate.reactive.panache.common.WithSession; +import io.quarkus.hibernate.reactive.panache.common.WithSessionOnDemand; import io.quarkus.hibernate.reactive.panache.common.WithTransaction; import io.quarkus.panache.common.Page; import io.quarkus.panache.common.Sort; @@ -62,6 +62,7 @@ String implement(ClassOutput classOutput, DataAccessImplementor dataAccessImplem // when injecting the resource in user beans: classCreator.addAnnotation(Alternative.class); classCreator.addAnnotation(Priority.class).add("value", Integer.MAX_VALUE); + classCreator.addAnnotation(WithSessionOnDemand.class); HibernateReactiveResourceMethodListenerImplementor resourceMethodListenerImplementor = new HibernateReactiveResourceMethodListenerImplementor( classCreator, resourceMethodListeners); @@ -82,7 +83,6 @@ String implement(ClassOutput classOutput, DataAccessImplementor dataAccessImplem private void implementList(ClassCreator classCreator, DataAccessImplementor dataAccessImplementor) { MethodCreator methodCreator = classCreator.getMethodCreator("list", Uni.class, Page.class, Sort.class); - methodCreator.addAnnotation(WithSession.class); ResultHandle page = methodCreator.getMethodParam(0); ResultHandle sort = methodCreator.getMethodParam(1); ResultHandle columns = methodCreator.invokeVirtualMethod(ofMethod(Sort.class, "getColumns", List.class), sort); @@ -98,7 +98,6 @@ private void implementList(ClassCreator classCreator, DataAccessImplementor data private void implementListWithQuery(ClassCreator classCreator, DataAccessImplementor dataAccessImplementor) { MethodCreator methodCreator = classCreator.getMethodCreator("list", Uni.class, Page.class, Sort.class, String.class, Map.class); - methodCreator.addAnnotation(WithSession.class); ResultHandle page = methodCreator.getMethodParam(0); ResultHandle sort = methodCreator.getMethodParam(1); ResultHandle query = methodCreator.getMethodParam(2); @@ -120,7 +119,6 @@ private void implementListWithQuery(ClassCreator classCreator, DataAccessImpleme */ private void implementCount(ClassCreator classCreator, DataAccessImplementor dataAccessImplementor) { MethodCreator methodCreator = classCreator.getMethodCreator("count", Uni.class); - methodCreator.addAnnotation(WithSession.class); methodCreator.returnValue(dataAccessImplementor.count(methodCreator)); methodCreator.close(); } @@ -132,7 +130,6 @@ 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); - methodCreator.addAnnotation(WithSession.class); ResultHandle page = methodCreator.getMethodParam(0); methodCreator.returnValue(dataAccessImplementor.pageCount(methodCreator, page)); methodCreator.close(); @@ -140,7 +137,6 @@ private void implementListPageCount(ClassCreator classCreator, DataAccessImpleme private void implementGet(ClassCreator classCreator, DataAccessImplementor dataAccessImplementor) { MethodCreator methodCreator = classCreator.getMethodCreator("get", Uni.class, Object.class); - methodCreator.addAnnotation(WithSession.class); ResultHandle id = methodCreator.getMethodParam(0); methodCreator.returnValue(dataAccessImplementor.findById(methodCreator, id)); methodCreator.close(); diff --git a/extensions/panache/hibernate-reactive-rest-data-panache/deployment/src/test/java/io/quarkus/hibernate/reactive/rest/data/panache/deployment/AbstractInjectResourcesMethodTest.java b/extensions/panache/hibernate-reactive-rest-data-panache/deployment/src/test/java/io/quarkus/hibernate/reactive/rest/data/panache/deployment/AbstractInjectResourcesMethodTest.java index 522d322d01d8bb..0a1b32680ab700 100644 --- a/extensions/panache/hibernate-reactive-rest-data-panache/deployment/src/test/java/io/quarkus/hibernate/reactive/rest/data/panache/deployment/AbstractInjectResourcesMethodTest.java +++ b/extensions/panache/hibernate-reactive-rest-data-panache/deployment/src/test/java/io/quarkus/hibernate/reactive/rest/data/panache/deployment/AbstractInjectResourcesMethodTest.java @@ -2,6 +2,7 @@ import static io.restassured.RestAssured.given; import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.is; import org.junit.jupiter.api.Test; @@ -14,4 +15,13 @@ void shouldGetListOfItems() { .then().statusCode(200) .and().body("id", contains(1, 2)); } + + @Test + void shouldCollectionByName() { + given().accept("application/json") + .when().get("/call/resource/collectionByName/full collection") + .then().statusCode(200) + .and().body("id", is("full")) + .and().body("name", is("full collection")); + } } diff --git a/extensions/panache/hibernate-reactive-rest-data-panache/deployment/src/test/java/io/quarkus/hibernate/reactive/rest/data/panache/deployment/entity/CollectionsResource.java b/extensions/panache/hibernate-reactive-rest-data-panache/deployment/src/test/java/io/quarkus/hibernate/reactive/rest/data/panache/deployment/entity/CollectionsResource.java index bcf2595d487a97..2282c0f5b8e273 100644 --- a/extensions/panache/hibernate-reactive-rest-data-panache/deployment/src/test/java/io/quarkus/hibernate/reactive/rest/data/panache/deployment/entity/CollectionsResource.java +++ b/extensions/panache/hibernate-reactive-rest-data-panache/deployment/src/test/java/io/quarkus/hibernate/reactive/rest/data/panache/deployment/entity/CollectionsResource.java @@ -1,8 +1,32 @@ package io.quarkus.hibernate.reactive.rest.data.panache.deployment.entity; +import java.util.Collections; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; + +import io.quarkus.hibernate.reactive.panache.common.WithSessionOnDemand; import io.quarkus.hibernate.reactive.rest.data.panache.PanacheEntityResource; import io.quarkus.rest.data.panache.ResourceProperties; +import io.smallrye.mutiny.Uni; @ResourceProperties(hal = true, paged = false, halCollectionName = "item-collections") +@WithSessionOnDemand public interface CollectionsResource extends PanacheEntityResource { + @GET + @Path("/name/{name}") + default Uni findByName(@PathParam("name") String name) { + return Collection.find("name = :name", Collections.singletonMap("name", name)).singleResult(); + } + + @POST + @Path("/name/{name}") + default Uni addByName(@PathParam("name") String name) { + Collection collection = new Collection(); + collection.id = name; + collection.name = name; + return Collection.persist(collection).onItem().transform(res -> collection); + } } diff --git a/extensions/panache/hibernate-reactive-rest-data-panache/deployment/src/test/java/io/quarkus/hibernate/reactive/rest/data/panache/deployment/entity/InjectionResource.java b/extensions/panache/hibernate-reactive-rest-data-panache/deployment/src/test/java/io/quarkus/hibernate/reactive/rest/data/panache/deployment/entity/InjectionResource.java index ef961bbd2922fd..1addf66232756f 100644 --- a/extensions/panache/hibernate-reactive-rest-data-panache/deployment/src/test/java/io/quarkus/hibernate/reactive/rest/data/panache/deployment/entity/InjectionResource.java +++ b/extensions/panache/hibernate-reactive-rest-data-panache/deployment/src/test/java/io/quarkus/hibernate/reactive/rest/data/panache/deployment/entity/InjectionResource.java @@ -5,6 +5,7 @@ import jakarta.inject.Inject; import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; import jakarta.ws.rs.Produces; import jakarta.ws.rs.core.MediaType; @@ -18,10 +19,20 @@ public class InjectionResource { @Inject ItemsResource itemsResource; + @Inject + CollectionsResource collectionsResource; + @GET @Path("/items") @Produces(MediaType.APPLICATION_JSON) public Uni> items() { return itemsResource.list(new Page(5), Sort.by("id")); } + + @GET + @Path("/collectionByName/{name}") + @Produces(MediaType.APPLICATION_JSON) + public Uni collectionByName(@PathParam("name") String name) { + return collectionsResource.findByName(name); + } } diff --git a/extensions/panache/hibernate-reactive-rest-data-panache/deployment/src/test/java/io/quarkus/hibernate/reactive/rest/data/panache/deployment/entity/PanacheEntityResourceGetMethodTest.java b/extensions/panache/hibernate-reactive-rest-data-panache/deployment/src/test/java/io/quarkus/hibernate/reactive/rest/data/panache/deployment/entity/PanacheEntityResourceGetMethodTest.java index 536d893409eeb3..6290512bb78d25 100644 --- a/extensions/panache/hibernate-reactive-rest-data-panache/deployment/src/test/java/io/quarkus/hibernate/reactive/rest/data/panache/deployment/entity/PanacheEntityResourceGetMethodTest.java +++ b/extensions/panache/hibernate-reactive-rest-data-panache/deployment/src/test/java/io/quarkus/hibernate/reactive/rest/data/panache/deployment/entity/PanacheEntityResourceGetMethodTest.java @@ -1,5 +1,9 @@ package io.quarkus.hibernate.reactive.rest.data.panache.deployment.entity; +import static io.restassured.RestAssured.given; +import static org.hamcrest.Matchers.is; + +import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; import io.quarkus.hibernate.reactive.rest.data.panache.deployment.AbstractGetMethodTest; @@ -15,4 +19,13 @@ class PanacheEntityResourceGetMethodTest extends AbstractGetMethodTest { EmptyListItem.class, EmptyListItemsResource.class) .addAsResource("application.properties") .addAsResource("import.sql")); + + @Test + void shouldCopyAdditionalMethodsAsResources() { + given().accept("application/json") + .when().get("/collections/name/full collection") + .then().statusCode(200) + .and().body("id", is("full")) + .and().body("name", is("full collection")); + } } diff --git a/extensions/panache/hibernate-reactive-rest-data-panache/deployment/src/test/java/io/quarkus/hibernate/reactive/rest/data/panache/deployment/entity/PanacheEntityResourcePostMethodTest.java b/extensions/panache/hibernate-reactive-rest-data-panache/deployment/src/test/java/io/quarkus/hibernate/reactive/rest/data/panache/deployment/entity/PanacheEntityResourcePostMethodTest.java index fea432427db380..d575e9c557c6d7 100644 --- a/extensions/panache/hibernate-reactive-rest-data-panache/deployment/src/test/java/io/quarkus/hibernate/reactive/rest/data/panache/deployment/entity/PanacheEntityResourcePostMethodTest.java +++ b/extensions/panache/hibernate-reactive-rest-data-panache/deployment/src/test/java/io/quarkus/hibernate/reactive/rest/data/panache/deployment/entity/PanacheEntityResourcePostMethodTest.java @@ -1,5 +1,9 @@ package io.quarkus.hibernate.reactive.rest.data.panache.deployment.entity; +import static io.restassured.RestAssured.given; +import static org.hamcrest.Matchers.is; + +import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; import io.quarkus.hibernate.reactive.rest.data.panache.deployment.AbstractPostMethodTest; @@ -14,4 +18,13 @@ class PanacheEntityResourcePostMethodTest extends AbstractPostMethodTest { Item.class, ItemsResource.class) .addAsResource("application.properties") .addAsResource("import.sql")); + + @Test + void shouldCopyAdditionalMethodsAsResources() { + given().accept("application/json") + .when().post("/collections/name/mycollection") + .then().statusCode(200) + .and().body("id", is("mycollection")) + .and().body("name", is("mycollection")); + } } diff --git a/extensions/panache/hibernate-reactive-rest-data-panache/deployment/src/test/java/io/quarkus/hibernate/reactive/rest/data/panache/deployment/repository/CollectionsResource.java b/extensions/panache/hibernate-reactive-rest-data-panache/deployment/src/test/java/io/quarkus/hibernate/reactive/rest/data/panache/deployment/repository/CollectionsResource.java index e24f791173789b..137642ce48a848 100644 --- a/extensions/panache/hibernate-reactive-rest-data-panache/deployment/src/test/java/io/quarkus/hibernate/reactive/rest/data/panache/deployment/repository/CollectionsResource.java +++ b/extensions/panache/hibernate-reactive-rest-data-panache/deployment/src/test/java/io/quarkus/hibernate/reactive/rest/data/panache/deployment/repository/CollectionsResource.java @@ -1,5 +1,12 @@ package io.quarkus.hibernate.reactive.rest.data.panache.deployment.repository; +import java.util.Collections; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; + import io.quarkus.hibernate.reactive.rest.data.panache.PanacheRepositoryResource; import io.quarkus.rest.data.panache.MethodProperties; import io.quarkus.rest.data.panache.ResourceProperties; @@ -10,4 +17,19 @@ public interface CollectionsResource extends PanacheRepositoryResource delete(String name); + + @GET + @Path("/name/{name}") + default Uni findByName(@PathParam("name") String name) { + return Collection.find("name = :name", Collections.singletonMap("name", name)).singleResult(); + } + + @POST + @Path("/name/{name}") + default Uni addByName(@PathParam("name") String name) { + Collection collection = new Collection(); + collection.id = name; + collection.name = name; + return Collection.persist(collection).onItem().transform(res -> collection); + } } diff --git a/extensions/panache/hibernate-reactive-rest-data-panache/deployment/src/test/java/io/quarkus/hibernate/reactive/rest/data/panache/deployment/repository/PanacheRepositoryResourceGetMethodTest.java b/extensions/panache/hibernate-reactive-rest-data-panache/deployment/src/test/java/io/quarkus/hibernate/reactive/rest/data/panache/deployment/repository/PanacheRepositoryResourceGetMethodTest.java index 1554e52727a68b..90932cfc7216a9 100644 --- a/extensions/panache/hibernate-reactive-rest-data-panache/deployment/src/test/java/io/quarkus/hibernate/reactive/rest/data/panache/deployment/repository/PanacheRepositoryResourceGetMethodTest.java +++ b/extensions/panache/hibernate-reactive-rest-data-panache/deployment/src/test/java/io/quarkus/hibernate/reactive/rest/data/panache/deployment/repository/PanacheRepositoryResourceGetMethodTest.java @@ -1,5 +1,9 @@ package io.quarkus.hibernate.reactive.rest.data.panache.deployment.repository; +import static io.restassured.RestAssured.given; +import static org.hamcrest.Matchers.is; + +import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; import io.quarkus.hibernate.reactive.rest.data.panache.deployment.AbstractGetMethodTest; @@ -16,4 +20,13 @@ class PanacheRepositoryResourceGetMethodTest extends AbstractGetMethodTest { EmptyListItemsResource.class) .addAsResource("application.properties") .addAsResource("import.sql")); + + @Test + void shouldCopyAdditionalMethodsAsResources() { + given().accept("application/json") + .when().get("/collections/name/full collection") + .then().statusCode(200) + .and().body("id", is("full")) + .and().body("name", is("full collection")); + } } diff --git a/extensions/panache/hibernate-reactive-rest-data-panache/deployment/src/test/java/io/quarkus/hibernate/reactive/rest/data/panache/deployment/repository/PanacheRepositoryResourcePostMethodTest.java b/extensions/panache/hibernate-reactive-rest-data-panache/deployment/src/test/java/io/quarkus/hibernate/reactive/rest/data/panache/deployment/repository/PanacheRepositoryResourcePostMethodTest.java index 4835a1080e3cc7..a4e39ce66abc31 100644 --- a/extensions/panache/hibernate-reactive-rest-data-panache/deployment/src/test/java/io/quarkus/hibernate/reactive/rest/data/panache/deployment/repository/PanacheRepositoryResourcePostMethodTest.java +++ b/extensions/panache/hibernate-reactive-rest-data-panache/deployment/src/test/java/io/quarkus/hibernate/reactive/rest/data/panache/deployment/repository/PanacheRepositoryResourcePostMethodTest.java @@ -1,5 +1,9 @@ package io.quarkus.hibernate.reactive.rest.data.panache.deployment.repository; +import static io.restassured.RestAssured.given; +import static org.hamcrest.Matchers.is; + +import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; import io.quarkus.hibernate.reactive.rest.data.panache.deployment.AbstractPostMethodTest; @@ -15,4 +19,13 @@ class PanacheRepositoryResourcePostMethodTest extends AbstractPostMethodTest { ItemsRepository.class) .addAsResource("application.properties") .addAsResource("import.sql")); + + @Test + void shouldCopyAdditionalMethodsAsResources() { + given().accept("application/json") + .when().post("/collections/name/mycollection") + .then().statusCode(200) + .and().body("id", is("mycollection")) + .and().body("name", is("mycollection")); + } } diff --git a/extensions/panache/rest-data-panache/deployment/src/main/java/io/quarkus/rest/data/panache/deployment/JaxRsResourceImplementor.java b/extensions/panache/rest-data-panache/deployment/src/main/java/io/quarkus/rest/data/panache/deployment/JaxRsResourceImplementor.java index 2a94eb832dabb3..eb31ccdaccef8f 100644 --- a/extensions/panache/rest-data-panache/deployment/src/main/java/io/quarkus/rest/data/panache/deployment/JaxRsResourceImplementor.java +++ b/extensions/panache/rest-data-panache/deployment/src/main/java/io/quarkus/rest/data/panache/deployment/JaxRsResourceImplementor.java @@ -37,6 +37,7 @@ class JaxRsResourceImplementor { private static final Logger LOGGER = Logger.getLogger(JaxRsResourceImplementor.class); private static final String OPENAPI_TAG_ANNOTATION = "org.eclipse.microprofile.openapi.annotations.tags.Tag"; + private static final String WITH_SESSION_ON_DEMAND_ANNOTATION = "io.quarkus.hibernate.reactive.panache.common.WithSessionOnDemand"; private final List methodImplementors; @@ -107,6 +108,9 @@ private void implementClassAnnotations(ClassCreator classCreator, ResourceMetada classCreator.addAnnotation(classAnnotation); } } + if (capabilities.isPresent(Capability.HIBERNATE_REACTIVE)) { + classCreator.addAnnotation(WITH_SESSION_ON_DEMAND_ANNOTATION); + } } private FieldDescriptor implementResourceField(ClassCreator classCreator, ResourceMetadata resourceMetadata) {