From 7ad47693d66dbe35f5b73da667c1caa38dff91f0 Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Mon, 26 Aug 2024 11:36:02 +0300 Subject: [PATCH] Register resource classes for reflection when ContainerResponseFilter exists This is needed because those filters can call setEntityStream which then forces the use of the slow path for calling writers Closes: #42537 --- .../deployment/ResteasyReactiveProcessor.java | 8 ++++++ .../common/model/InterceptorContainer.java | 4 +++ ...ityStreamSettingContainerResponseFilter.kt | 28 +++++++++++++++++++ .../kotlin/ReactiveGreetingResource.kt | 2 +- .../kotlin/ReactiveGreetingResourceTest.kt | 4 ++- 5 files changed, 44 insertions(+), 2 deletions(-) create mode 100644 integration-tests/resteasy-reactive-kotlin/standard/src/main/kotlin/io/quarkus/it/resteasy/reactive/kotlin/EntityStreamSettingContainerResponseFilter.kt diff --git a/extensions/resteasy-reactive/rest/deployment/src/main/java/io/quarkus/resteasy/reactive/server/deployment/ResteasyReactiveProcessor.java b/extensions/resteasy-reactive/rest/deployment/src/main/java/io/quarkus/resteasy/reactive/server/deployment/ResteasyReactiveProcessor.java index 68c8b01978fd58..49c2bf93a45078 100644 --- a/extensions/resteasy-reactive/rest/deployment/src/main/java/io/quarkus/resteasy/reactive/server/deployment/ResteasyReactiveProcessor.java +++ b/extensions/resteasy-reactive/rest/deployment/src/main/java/io/quarkus/resteasy/reactive/server/deployment/ResteasyReactiveProcessor.java @@ -1141,6 +1141,7 @@ public void additionalReflection(BeanArchiveIndexBuildItem beanArchiveIndexBuild SetupEndpointsResultBuildItem setupEndpointsResult, List messageBodyReaderBuildItems, List messageBodyWriterBuildItems, + ResourceInterceptorsBuildItem resourceInterceptorsBuildItem, BuildProducer producer) { List resourceClasses = setupEndpointsResult.getResourceClasses(); IndexView index = beanArchiveIndexBuildItem.getIndex(); @@ -1185,6 +1186,13 @@ public void additionalReflection(BeanArchiveIndexBuildItem beanArchiveIndexBuild } } } + + // when a ContainerResponseFilter exists, it can potentially do responseContext.setEntityStream() + // which then forces the use of the slow path for calling writers + if (!resourceInterceptorsBuildItem.getResourceInterceptors().getContainerResponseFilters().isEmpty()) { + serializersRequireResourceReflection = true; + } + if (serializersRequireResourceReflection) { producer.produce(ReflectiveClassBuildItem .builder(resourceClasses.stream().map(ResourceClass::getClassName).toArray(String[]::new)) diff --git a/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/model/InterceptorContainer.java b/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/model/InterceptorContainer.java index b6d52e624ed96d..075e8e17291483 100644 --- a/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/model/InterceptorContainer.java +++ b/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/model/InterceptorContainer.java @@ -33,6 +33,10 @@ public void sort() { Collections.sort(nameResourceInterceptors); } + public boolean isEmpty() { + return globalResourceInterceptors.isEmpty() && nameResourceInterceptors.isEmpty(); + } + public ResourceInterceptor create() { return new ResourceInterceptor<>(); } diff --git a/integration-tests/resteasy-reactive-kotlin/standard/src/main/kotlin/io/quarkus/it/resteasy/reactive/kotlin/EntityStreamSettingContainerResponseFilter.kt b/integration-tests/resteasy-reactive-kotlin/standard/src/main/kotlin/io/quarkus/it/resteasy/reactive/kotlin/EntityStreamSettingContainerResponseFilter.kt new file mode 100644 index 00000000000000..c39a20d992e0fd --- /dev/null +++ b/integration-tests/resteasy-reactive-kotlin/standard/src/main/kotlin/io/quarkus/it/resteasy/reactive/kotlin/EntityStreamSettingContainerResponseFilter.kt @@ -0,0 +1,28 @@ +package io.quarkus.it.resteasy.reactive.kotlin + +import jakarta.ws.rs.container.ContainerRequestContext +import jakarta.ws.rs.container.ContainerResponseContext +import jakarta.ws.rs.container.ContainerResponseFilter +import jakarta.ws.rs.ext.Provider +import java.io.ByteArrayInputStream +import org.jboss.resteasy.reactive.server.spi.ResteasyReactiveContainerRequestContext + +@Provider +class EntityStreamSettingContainerResponseFilter : ContainerResponseFilter { + override fun filter( + requestContext: ContainerRequestContext?, + responseContext: ContainerResponseContext? + ) { + if (requestContext is ResteasyReactiveContainerRequestContext) { + if ( + "hello".equals( + requestContext.serverRequestContext.resteasyReactiveResourceInfo.name + ) + ) { + responseContext?.setEntity( + ByteArrayInputStream("Hello Quarkus REST".toByteArray(Charsets.UTF_8)) + ) + } + } + } +} diff --git a/integration-tests/resteasy-reactive-kotlin/standard/src/main/kotlin/io/quarkus/it/resteasy/reactive/kotlin/ReactiveGreetingResource.kt b/integration-tests/resteasy-reactive-kotlin/standard/src/main/kotlin/io/quarkus/it/resteasy/reactive/kotlin/ReactiveGreetingResource.kt index 37aa578a98faa5..96915bbf3cbfd5 100644 --- a/integration-tests/resteasy-reactive-kotlin/standard/src/main/kotlin/io/quarkus/it/resteasy/reactive/kotlin/ReactiveGreetingResource.kt +++ b/integration-tests/resteasy-reactive-kotlin/standard/src/main/kotlin/io/quarkus/it/resteasy/reactive/kotlin/ReactiveGreetingResource.kt @@ -30,7 +30,7 @@ class ReactiveGreetingResource @Inject constructor(val req: RequestScopedKotlinC @GET @Produces(MediaType.TEXT_PLAIN) @Path("/{name}") - suspend fun hello(name: String): String { + suspend fun namedHello(name: String): String { delay(50) return "Hello $name" } diff --git a/integration-tests/resteasy-reactive-kotlin/standard/src/test/kotlin/io/quarkus/it/resteasy/reactive/kotlin/ReactiveGreetingResourceTest.kt b/integration-tests/resteasy-reactive-kotlin/standard/src/test/kotlin/io/quarkus/it/resteasy/reactive/kotlin/ReactiveGreetingResourceTest.kt index a2bad8227df388..3c965bacfd132a 100644 --- a/integration-tests/resteasy-reactive-kotlin/standard/src/test/kotlin/io/quarkus/it/resteasy/reactive/kotlin/ReactiveGreetingResourceTest.kt +++ b/integration-tests/resteasy-reactive-kotlin/standard/src/test/kotlin/io/quarkus/it/resteasy/reactive/kotlin/ReactiveGreetingResourceTest.kt @@ -19,7 +19,9 @@ class ReactiveGreetingResourceTest { When { get("/hello-resteasy-reactive/") } Then { statusCode(200) - body(`is`("Hello RestEASY Reactive")) + body( + `is`("Hello Quarkus REST") + ) // the result comes from EntityStreamSettingContainerResponseFilter } }