From 2f01c66a775599110c96ec24cbd1c71982ba8417 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 (cherry picked from commit 2a050f7db0fb52282d715fe444ea17ce0fb204bd) --- .../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 ba6ec3f69909e..5bab72e60b644 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 @@ -1078,6 +1078,7 @@ public void additionalReflection(BeanArchiveIndexBuildItem beanArchiveIndexBuild SetupEndpointsResultBuildItem setupEndpointsResult, List messageBodyReaderBuildItems, List messageBodyWriterBuildItems, + ResourceInterceptorsBuildItem resourceInterceptorsBuildItem, BuildProducer producer) { List resourceClasses = setupEndpointsResult.getResourceClasses(); IndexView index = beanArchiveIndexBuildItem.getIndex(); @@ -1122,6 +1123,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 b6d52e624ed96..075e8e1729148 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 0000000000000..c39a20d992e0f --- /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 37aa578a98faa..96915bbf3cbfd 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 a2bad8227df38..3c965bacfd132 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 } }