diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/main/java/io/quarkus/resteasy/reactive/server/deployment/ResteasyReactiveProcessor.java b/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/main/java/io/quarkus/resteasy/reactive/server/deployment/ResteasyReactiveProcessor.java index d3c4f9102d540..fdfab1e721441 100644 --- a/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/main/java/io/quarkus/resteasy/reactive/server/deployment/ResteasyReactiveProcessor.java +++ b/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/main/java/io/quarkus/resteasy/reactive/server/deployment/ResteasyReactiveProcessor.java @@ -730,7 +730,7 @@ private FilterClassIntrospector createFilterClassIntrospector() { return ab.get(); } - // We want to add @Typed to resources and providers so that they can be resolved as CDI bean using purely their + // We want to add @Typed to resources, beanparams and providers so that they can be resolved as CDI bean using purely their // class as a bean type. This removes any ambiguity that potential subclasses may have. @BuildStep public void transformEndpoints( @@ -744,6 +744,10 @@ public void transformEndpoints( allResources.addAll(resourceScanningResultBuildItem.getResult().getScannedResources().keySet()); allResources.addAll(resourceScanningResultBuildItem.getResult().getPossibleSubResources().keySet()); + // all found bean params + Set beanParams = resourceScanningResultBuildItem.getResult() + .getBeanParams(); + // discovered filters and interceptors Set filtersAndInterceptors = new HashSet<>(); InterceptorContainer readerInterceptors = resourceInterceptorsBuildItem.getResourceInterceptors() @@ -788,6 +792,14 @@ public void transform(TransformationContext context) { && clazz.declaredAnnotation(ResteasyReactiveDotNames.TYPED) == null) { // Add @Typed(MyResource.class) context.transform().add(createTypedAnnotationInstance(clazz, beanArchiveIndexBuildItem)).done(); + return; + } + // check if the class is a bean param + if (beanParams.contains(clazz.name().toString()) + && clazz.declaredAnnotation(ResteasyReactiveDotNames.TYPED) == null) { + // Add @Typed(MyBean.class) + context.transform().add(createTypedAnnotationInstance(clazz, beanArchiveIndexBuildItem)).done(); + return; } } })); diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/beanparam/BeanParamTest.java b/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/beanparam/BeanParamTest.java new file mode 100644 index 0000000000000..85a739e30b75a --- /dev/null +++ b/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/beanparam/BeanParamTest.java @@ -0,0 +1,104 @@ +package io.quarkus.resteasy.reactive.server.test.beanparam; + +import javax.ws.rs.BeanParam; +import javax.ws.rs.CookieParam; +import javax.ws.rs.FormParam; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.QueryParam; + +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; + +public class BeanParamTest { + @RegisterExtension + static final QuarkusUnitTest TEST = new QuarkusUnitTest() + .setArchiveProducer(() -> { + return ShrinkWrap.create(JavaArchive.class) + .addClasses(MyBeanParamWithFieldsAndProperties.class, Top.class); + }); + + @Test + void shouldDeployWithoutIssues() { + // we only need to check that it deploys + } + + public static class Top { + @PathParam("pathParam") + private String pathParam = "pathParam"; + + public String getPathParam() { + return pathParam; + } + + public void setPathParam(String pathParam) { + this.pathParam = pathParam; + } + } + + public static class MyBeanParamWithFieldsAndProperties extends Top { + @HeaderParam("headerParam") + private String headerParam = "headerParam"; + @CookieParam("cookieParam") + private String cookieParam = "cookieParam"; + @FormParam("formParam") + private String formParam = "formParam"; + @QueryParam("queryParam") + private String queryParam = "queryParam"; + + // FIXME: Matrix not supported + + public String getHeaderParam() { + return headerParam; + } + + public void setHeaderParam(String headerParam) { + this.headerParam = headerParam; + } + + public String getCookieParam() { + return cookieParam; + } + + public void setCookieParam(String cookieParam) { + this.cookieParam = cookieParam; + } + + public String getFormParam() { + return formParam; + } + + public void setFormParam(String formParam) { + this.formParam = formParam; + } + + public String getQueryParam() { + return queryParam; + } + + public void setQueryParam(String queryParam) { + this.queryParam = queryParam; + } + } + + @Path("/") + public static class Resource { + @Path("/a/{restPathDefault}/{restPath_Overridden}/{pathParam}") + @POST + public String beanParamWithFields(@BeanParam MyBeanParamWithFieldsAndProperties p) { + return null; + } + + @Path("/b/{pathParam}") + @POST + public String beanParamWithFields(@BeanParam Top p) { + return null; + } + } +}