From 35077cefb566985b925f95ce589c989257368290 Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Fri, 2 Jun 2023 13:43:38 +0300 Subject: [PATCH] Remove the need for @Unremoveable producer with custom @Context types Sparked by: https://stackoverflow.com/q/76387974/2504224 --- .../ResteasyReactiveCDIProcessor.java | 39 ++++++++- .../test/simple/CustomContextTypeTest.java | 79 +++++++++++++++++++ 2 files changed, 114 insertions(+), 4 deletions(-) create mode 100644 extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/simple/CustomContextTypeTest.java diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/main/java/io/quarkus/resteasy/reactive/server/deployment/ResteasyReactiveCDIProcessor.java b/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/main/java/io/quarkus/resteasy/reactive/server/deployment/ResteasyReactiveCDIProcessor.java index f60a04baf9da6..a9c80ff5f2398 100644 --- a/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/main/java/io/quarkus/resteasy/reactive/server/deployment/ResteasyReactiveCDIProcessor.java +++ b/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/main/java/io/quarkus/resteasy/reactive/server/deployment/ResteasyReactiveCDIProcessor.java @@ -1,16 +1,23 @@ package io.quarkus.resteasy.reactive.server.deployment; +import static org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames.APPLICATION_PATH; +import static org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames.CONTEXT; +import static org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames.PATH; +import static org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames.PROVIDER; + import java.lang.reflect.Modifier; import java.util.ArrayList; +import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Optional; import jakarta.ws.rs.BeanParam; +import org.jboss.jandex.AnnotationInstance; +import org.jboss.jandex.AnnotationTarget; import org.jboss.jandex.ClassInfo; import org.jboss.jandex.DotName; -import org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames; import org.jboss.resteasy.reactive.common.processor.scanning.ResourceScanningResult; import org.jboss.resteasy.reactive.server.injection.ContextProducers; import org.jboss.resteasy.reactive.server.processor.util.ResteasyReactiveServerDotNames; @@ -18,6 +25,7 @@ import io.quarkus.arc.deployment.AdditionalBeanBuildItem; import io.quarkus.arc.deployment.AutoInjectAnnotationBuildItem; import io.quarkus.arc.deployment.BeanDefiningAnnotationBuildItem; +import io.quarkus.arc.deployment.UnremovableBeanBuildItem; import io.quarkus.arc.processor.BuiltinScope; import io.quarkus.arc.processor.DotNames; import io.quarkus.deployment.annotations.BuildProducer; @@ -45,15 +53,38 @@ AutoInjectAnnotationBuildItem contextInjection( @BuildStep void beanDefiningAnnotations(BuildProducer beanDefiningAnnotations) { beanDefiningAnnotations - .produce(new BeanDefiningAnnotationBuildItem(ResteasyReactiveDotNames.PATH, BuiltinScope.SINGLETON.getName())); + .produce(new BeanDefiningAnnotationBuildItem(PATH, BuiltinScope.SINGLETON.getName())); beanDefiningAnnotations - .produce(new BeanDefiningAnnotationBuildItem(ResteasyReactiveDotNames.APPLICATION_PATH, + .produce(new BeanDefiningAnnotationBuildItem(APPLICATION_PATH, BuiltinScope.SINGLETON.getName())); beanDefiningAnnotations - .produce(new BeanDefiningAnnotationBuildItem(ResteasyReactiveDotNames.PROVIDER, + .produce(new BeanDefiningAnnotationBuildItem(PROVIDER, BuiltinScope.SINGLETON.getName())); } + @BuildStep + void unremovableContextMethodParams(Optional resourceScanningResultBuildItem, + BuildProducer producer) { + + if (resourceScanningResultBuildItem.isEmpty()) { + return; + } + + Collection resourceClasses = resourceScanningResultBuildItem.get().getResult().getScannedResources() + .values(); + for (ClassInfo resourceClass : resourceClasses) { + if (resourceClass.annotationsMap().containsKey(CONTEXT)) { + for (AnnotationInstance instance : resourceClass.annotationsMap().get(CONTEXT)) { + if (instance.target().kind() != AnnotationTarget.Kind.METHOD_PARAMETER) { + continue; + } + producer.produce(UnremovableBeanBuildItem + .beanTypes(instance.target().asMethodParameter().type().name())); + } + } + } + } + @BuildStep void subResourcesAsBeans(ResourceScanningResultBuildItem setupEndpointsResult, List subResourcesAsBeans, diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/simple/CustomContextTypeTest.java b/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/simple/CustomContextTypeTest.java new file mode 100644 index 0000000000000..352e58b73d691 --- /dev/null +++ b/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/simple/CustomContextTypeTest.java @@ -0,0 +1,79 @@ +package io.quarkus.resteasy.reactive.server.test.simple; + +import static org.hamcrest.CoreMatchers.is; + +import java.util.function.Supplier; + +import jakarta.enterprise.context.RequestScoped; +import jakarta.inject.Singleton; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.HttpHeaders; + +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; +import io.restassured.RestAssured; + +public class CustomContextTypeTest { + + @RegisterExtension + static QuarkusUnitTest test = new QuarkusUnitTest() + .setArchiveProducer(new Supplier<>() { + @Override + public JavaArchive get() { + return ShrinkWrap.create(JavaArchive.class) + .addClasses(TestResource.class, CustomType.class, CustomTypeProducer.class); + } + }); + + @Test + public void firstTest() { + RestAssured.given().headers("foo", "bar") + .get("/test") + .then().statusCode(200).body(is("bar")); + } + + @Test + public void secondTest() { + RestAssured.given().headers("foo", "baz") + .get("/test") + .then().statusCode(200).body(is("baz")); + } + + @Path("/test") + public static class TestResource { + + @GET + public String get(@Context CustomType customType) { + return customType.getValue(); + } + } + + public static class CustomType { + private final String value; + + public CustomType(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + } + + @Singleton + public static class CustomTypeProducer { + + @Produces + @RequestScoped + public CustomType customType(HttpHeaders headers) { + return new CustomType(headers.getHeaderString("foo")); + } + } +}