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 5d2e44fb2f4b0d..d7ccf1c31926f3 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 @@ -42,6 +42,8 @@ import javax.ws.rs.ext.MessageBodyReader; import javax.ws.rs.ext.MessageBodyWriter; import javax.ws.rs.ext.Providers; +import javax.ws.rs.ext.ReaderInterceptor; +import javax.ws.rs.ext.WriterInterceptor; import org.eclipse.microprofile.config.Config; import org.eclipse.microprofile.config.ConfigProvider; @@ -57,6 +59,8 @@ import org.jboss.resteasy.reactive.common.core.Serialisers; import org.jboss.resteasy.reactive.common.core.SingletonBeanFactory; import org.jboss.resteasy.reactive.common.model.InjectableBean; +import org.jboss.resteasy.reactive.common.model.InterceptorContainer; +import org.jboss.resteasy.reactive.common.model.PreMatchInterceptorContainer; import org.jboss.resteasy.reactive.common.model.ResourceClass; import org.jboss.resteasy.reactive.common.model.ResourceDynamicFeature; import org.jboss.resteasy.reactive.common.model.ResourceFeature; @@ -718,12 +722,39 @@ private FilterClassIntrospector createFilterClassIntrospector() { return ab.get(); } - // We want to add @Typed to endpoints so that they can be resolved as CDI bean using purely their class as a bean type - // this removes any interference with potential subclasses having same bean types + // We want to add @Typed to resources 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( + ResourceScanningResultBuildItem resourceScanningResultBuildItem, + ResourceInterceptorsBuildItem resourceInterceptorsBuildItem, BuildProducer annotationsTransformer) { + // all found resources and sub-resources + Set allResources = new HashSet<>(); + allResources.addAll(resourceScanningResultBuildItem.getResult().getScannedResources().keySet()); + allResources.addAll(resourceScanningResultBuildItem.getResult().getPossibleSubResources().keySet()); + + // discovered filters and interceptors + Set filtersAndInterceptors = new HashSet<>(); + InterceptorContainer readerInterceptors = resourceInterceptorsBuildItem.getResourceInterceptors() + .getReaderInterceptors(); + readerInterceptors.getNameResourceInterceptors().forEach(i -> filtersAndInterceptors.add(i.getClassName())); + readerInterceptors.getGlobalResourceInterceptors().forEach(i -> filtersAndInterceptors.add(i.getClassName())); + InterceptorContainer writerInterceptors = resourceInterceptorsBuildItem.getResourceInterceptors() + .getWriterInterceptors(); + writerInterceptors.getNameResourceInterceptors().forEach(i -> filtersAndInterceptors.add(i.getClassName())); + writerInterceptors.getGlobalResourceInterceptors().forEach(i -> filtersAndInterceptors.add(i.getClassName())); + PreMatchInterceptorContainer containerRequestFilters = resourceInterceptorsBuildItem + .getResourceInterceptors().getContainerRequestFilters(); + containerRequestFilters.getPreMatchInterceptors().forEach(i -> filtersAndInterceptors.add(i.getClassName())); + containerRequestFilters.getNameResourceInterceptors().forEach(i -> filtersAndInterceptors.add(i.getClassName())); + containerRequestFilters.getGlobalResourceInterceptors().forEach(i -> filtersAndInterceptors.add(i.getClassName())); + InterceptorContainer containerResponseFilters = resourceInterceptorsBuildItem + .getResourceInterceptors().getContainerResponseFilters(); + containerResponseFilters.getGlobalResourceInterceptors().forEach(i -> filtersAndInterceptors.add(i.getClassName())); + containerResponseFilters.getNameResourceInterceptors().forEach(i -> filtersAndInterceptors.add(i.getClassName())); + annotationsTransformer.produce(new io.quarkus.arc.deployment.AnnotationsTransformerBuildItem( new io.quarkus.arc.processor.AnnotationsTransformer() { @@ -735,10 +766,16 @@ public boolean appliesTo(AnnotationTarget.Kind kind) { @Override public void transform(TransformationContext context) { ClassInfo clazz = context.getTarget().asClass(); - // only adding to Path, since adding it to Provider doesn't seem necessary and in fact - // causes other failures - if ((clazz.declaredAnnotation(ResteasyReactiveDotNames.PATH) != null - || clazz.declaredAnnotation(ResteasyReactiveDotNames.PROVIDER) != null) + // check if the class is one of resources/sub-resources + if (allResources.contains(clazz.name()) + && clazz.declaredAnnotation(ResteasyReactiveDotNames.TYPED) == null) { + context.transform().add(createTypedAnnotationInstance(clazz)).done(); + return; + } + // check if the class is one of providers, either explicitly declaring the annotation + // or discovered as resource interceptor or filter + if ((clazz.declaredAnnotation(ResteasyReactiveDotNames.PROVIDER) != null + || filtersAndInterceptors.contains(clazz.name().toString())) && clazz.declaredAnnotation(ResteasyReactiveDotNames.TYPED) == null) { // Add @Typed(MyResource.class) context.transform().add(createTypedAnnotationInstance(clazz)).done();