From edbc29c88760c927cf6c59c4e145880369a93bd1 Mon Sep 17 00:00:00 2001 From: Matej Novotny Date: Wed, 5 Oct 2022 15:30:53 +0200 Subject: [PATCH 1/3] Revisit the non-standard behavior of ArcContainer#instanceSupplier() Modify RR and Undertow processors to add @Typed to the resources they discover as beans --- .../io/quarkus/arc/runtime/BeanContainer.java | 9 ++- .../deployment/ResteasyReactiveProcessor.java | 73 +++++++++++++++++++ .../test/response/ChunkedResponseTest.java | 19 ++++- .../deployment/UndertowBuildStep.java | 38 ++++++++++ .../io/quarkus/arc/impl/ArcContainerImpl.java | 15 +--- .../processor/ResteasyReactiveDotNames.java | 2 + 6 files changed, 139 insertions(+), 17 deletions(-) diff --git a/extensions/arc/runtime/src/main/java/io/quarkus/arc/runtime/BeanContainer.java b/extensions/arc/runtime/src/main/java/io/quarkus/arc/runtime/BeanContainer.java index 737a99bd19da4..df187a9e0c94c 100644 --- a/extensions/arc/runtime/src/main/java/io/quarkus/arc/runtime/BeanContainer.java +++ b/extensions/arc/runtime/src/main/java/io/quarkus/arc/runtime/BeanContainer.java @@ -20,9 +20,12 @@ default T instance(Class type, Annotation... qualifiers) { } /** - * Note that if there are multiple sub classes of the given type this will return the exact match. This means - * that this can be used to directly instantiate superclasses of other beans without causing problems. This behavior differs - * to standard CDI rules where an ambiguous dependency would exist. + * Returns an instance factory for given bean type and qualifiers. + *

+ * This method follows standard CDI rules meaning that if there are two or more beans, an ambiguous dependency + * exception is thrown. + * Note that the factory itself is still allowed to return {@code null} if there is no matching bean which allows + * for fallback implementations. * * @param type * @param qualifiers 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 e239f253d6bcf..d7ccf1c31926f 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,6 +722,75 @@ 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 + // 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() { + + @Override + public boolean appliesTo(AnnotationTarget.Kind kind) { + return kind == AnnotationTarget.Kind.CLASS; + } + + @Override + public void transform(TransformationContext context) { + ClassInfo clazz = context.getTarget().asClass(); + // 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(); + } + } + })); + } + + private AnnotationInstance createTypedAnnotationInstance(ClassInfo clazz) { + return AnnotationInstance.create(ResteasyReactiveDotNames.TYPED, clazz, + new AnnotationValue[] { AnnotationValue.createArrayValue("value", + new AnnotationValue[] { AnnotationValue.createClassValue("value", + Type.create(clazz.name(), Type.Kind.CLASS)) }) }); + } + private Collection additionalContextTypes(List contextTypeBuildItems) { if (contextTypeBuildItems.isEmpty()) { return CONTEXT_TYPES; diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/response/ChunkedResponseTest.java b/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/response/ChunkedResponseTest.java index 4af67db4b5c03..1bd68e6a2d9bb 100644 --- a/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/response/ChunkedResponseTest.java +++ b/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/response/ChunkedResponseTest.java @@ -30,7 +30,7 @@ public class ChunkedResponseTest { static QuarkusUnitTest runner = new QuarkusUnitTest() .withApplicationRoot((jar) -> jar .addClasses(HelloResource.class) - .addAsResource(new StringAsset("quarkus.rest.output-buffer-size = 256"), + .addAsResource(new StringAsset("quarkus.resteasy-reactive.output-buffer-size = 256"), "application.properties")); @Test @@ -68,7 +68,22 @@ public String helloSmall() { } @Provider - public static final class CustomStringMessageBodyWriter extends ServerStringMessageBodyHandler { + public static class CustomStringMessageBodyWriter extends ServerStringMessageBodyHandler { + + @Override + public void writeResponse(Object o, Type genericType, ServerRequestContext context) + throws WebApplicationException { + + try (OutputStream stream = context.getOrCreateOutputStream()) { + stream.write(((String) o).getBytes()); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + } + + @Provider + public static final class CustomStringMessageBodyWriter2 extends CustomStringMessageBodyWriter { @Override public void writeResponse(Object o, Type genericType, ServerRequestContext context) diff --git a/extensions/undertow/deployment/src/main/java/io/quarkus/undertow/deployment/UndertowBuildStep.java b/extensions/undertow/deployment/src/main/java/io/quarkus/undertow/deployment/UndertowBuildStep.java index 68f18b5765624..6758ef0245712 100644 --- a/extensions/undertow/deployment/src/main/java/io/quarkus/undertow/deployment/UndertowBuildStep.java +++ b/extensions/undertow/deployment/src/main/java/io/quarkus/undertow/deployment/UndertowBuildStep.java @@ -22,6 +22,7 @@ import javax.annotation.security.RunAs; import javax.enterprise.context.ApplicationScoped; import javax.enterprise.context.SessionScoped; +import javax.enterprise.inject.Typed; import javax.inject.Inject; import javax.servlet.ServletContainerInitializer; import javax.servlet.ServletContext; @@ -78,12 +79,14 @@ import org.jboss.metadata.web.spec.WebResourceCollectionMetaData; import io.quarkus.arc.deployment.AdditionalBeanBuildItem; +import io.quarkus.arc.deployment.AnnotationsTransformerBuildItem; import io.quarkus.arc.deployment.BeanContainerBuildItem; import io.quarkus.arc.deployment.ConfigInjectionStaticInitBuildItem; import io.quarkus.arc.deployment.ContextRegistrationPhaseBuildItem; import io.quarkus.arc.deployment.ContextRegistrationPhaseBuildItem.ContextConfiguratorBuildItem; import io.quarkus.arc.deployment.CustomScopeBuildItem; import io.quarkus.arc.deployment.SyntheticBeanBuildItem; +import io.quarkus.arc.processor.AnnotationsTransformer; import io.quarkus.deployment.Capabilities; import io.quarkus.deployment.Capability; import io.quarkus.deployment.Feature; @@ -142,6 +145,7 @@ public class UndertowBuildStep { public static final DotName DECLARE_ROLES = DotName.createSimple(DeclareRoles.class.getName()); public static final DotName MULTIPART_CONFIG = DotName.createSimple(MultipartConfig.class.getName()); public static final DotName SERVLET_SECURITY = DotName.createSimple(ServletSecurity.class.getName()); + public static final DotName TYPED = DotName.createSimple(Typed.class.getName()); protected static final String SERVLET_CONTAINER_INITIALIZER = "META-INF/services/javax.servlet.ServletContainerInitializer"; protected static final DotName HANDLES_TYPES = DotName.createSimple(HandlesTypes.class.getName()); @@ -335,6 +339,40 @@ private boolean hasSecurityCapability(final Capabilities capabilities) { return capabilities.isCapabilityWithPrefixPresent(Capability.SECURITY); } + @BuildStep + public void addTypedAnnotations( + BuildProducer annotationsTransformer) { + + annotationsTransformer.produce(new io.quarkus.arc.deployment.AnnotationsTransformerBuildItem( + new AnnotationsTransformer() { + + @Override + public boolean appliesTo(AnnotationTarget.Kind kind) { + return kind == AnnotationTarget.Kind.CLASS; + } + + @Override + public void transform(TransformationContext context) { + ClassInfo clazz = context.getTarget().asClass(); + if (clazz.declaredAnnotation(WEB_SERVLET) != null + || clazz.declaredAnnotation(WEB_FILTER) != null + || clazz.declaredAnnotation(WEB_LISTENER) != null) { + if (clazz.declaredAnnotation(TYPED) == null) { + // Add @Typed(MyResource.class) + context.transform().add(createTypedAnnotationInstance(clazz)).done(); + } + } + } + })); + } + + private AnnotationInstance createTypedAnnotationInstance(ClassInfo clazz) { + return AnnotationInstance.create(TYPED, clazz, + new AnnotationValue[] { AnnotationValue.createArrayValue("value", + new AnnotationValue[] { AnnotationValue.createClassValue("value", + Type.create(clazz.name(), Type.Kind.CLASS)) }) }); + } + @Record(STATIC_INIT) @BuildStep() public ServletDeploymentManagerBuildItem build(List servlets, diff --git a/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/ArcContainerImpl.java b/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/ArcContainerImpl.java index 71cfa5cf8cc6d..94230917eb52c 100644 --- a/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/ArcContainerImpl.java +++ b/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/ArcContainerImpl.java @@ -241,20 +241,11 @@ public Supplier> instanceSupplier(Class type, Annotatio qualifiers = new Annotation[] { Default.Literal.INSTANCE }; } Set> resolvedBeans = resolved.getValue(new Resolvable(type, qualifiers)); - Set> filteredBean = resolvedBeans; if (resolvedBeans.size() > 1) { - //if there are multiple beans we look for an exact match - //this method is only called with the exact type required - //so ignoring subclasses is the correct behaviour - filteredBean = new HashSet<>(); - for (InjectableBean i : resolvedBeans) { - if (i.getBeanClass().equals(type)) { - filteredBean.add(i); - } - } + throw new AmbiguousResolutionException("Beans: " + resolvedBeans); } - InjectableBean bean = filteredBean.size() != 1 ? null - : (InjectableBean) filteredBean.iterator().next(); + InjectableBean bean = resolvedBeans.size() != 1 ? null + : (InjectableBean) resolvedBeans.iterator().next(); if (bean == null) { return null; } diff --git a/independent-projects/resteasy-reactive/common/processor/src/main/java/org/jboss/resteasy/reactive/common/processor/ResteasyReactiveDotNames.java b/independent-projects/resteasy-reactive/common/processor/src/main/java/org/jboss/resteasy/reactive/common/processor/ResteasyReactiveDotNames.java index 6c9a24d14986d..c86e07b6d04ac 100644 --- a/independent-projects/resteasy-reactive/common/processor/src/main/java/org/jboss/resteasy/reactive/common/processor/ResteasyReactiveDotNames.java +++ b/independent-projects/resteasy-reactive/common/processor/src/main/java/org/jboss/resteasy/reactive/common/processor/ResteasyReactiveDotNames.java @@ -25,6 +25,7 @@ import javax.annotation.Priority; import javax.enterprise.context.ApplicationScoped; import javax.enterprise.context.RequestScoped; +import javax.enterprise.inject.Typed; import javax.enterprise.inject.Vetoed; import javax.inject.Inject; import javax.inject.Singleton; @@ -166,6 +167,7 @@ public final class ResteasyReactiveDotNames { public static final DotName DEFAULT_VALUE = DotName.createSimple(DefaultValue.class.getName()); public static final DotName NAME_BINDING = DotName.createSimple(NameBinding.class.getName()); public static final DotName VETOED = DotName.createSimple(Vetoed.class.getName()); + public static final DotName TYPED = DotName.createSimple(Typed.class.getName()); public static final DotName APPLICATION_SCOPED = DotName.createSimple(ApplicationScoped.class.getName()); public static final DotName SINGLETON = DotName.createSimple(Singleton.class.getName()); public static final DotName REQUEST_SCOPED = DotName.createSimple(RequestScoped.class.getName()); From dfb8e542bf77f774ff3cf5cbd8b7e9ab048e06a8 Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Mon, 10 Oct 2022 11:17:19 +0300 Subject: [PATCH 2/3] Ensure that providers in RESTEasy Reactive common module aren't discoverable. These providers are registered manually, but previously because they were annotated with @Provider, they could be inadvertently registered as application classes in some test cases (essentially if an actual application class extended them). Added note about sorting - this note is needed in order to folks debugging in the future from going down the wrong path and having the TCK fail. Fix ChunkedResponseTest to be spec compliant. --- .../test/response/ChunkedResponseTest.java | 39 +++++++++++++------ .../reactive/common/core/Serialisers.java | 6 ++- .../ServerBooleanMessageBodyHandler.java | 2 - .../ServerByteArrayMessageBodyHandler.java | 2 - .../ServerCharArrayMessageBodyHandler.java | 2 - .../ServerCharacterMessageBodyHandler.java | 2 - .../ServerDefaultTextPlainBodyHandler.java | 2 - .../serialisers/ServerFileBodyHandler.java | 2 - .../ServerFilePartBodyHandler.java | 2 - .../ServerFormUrlEncodedProvider.java | 2 - .../ServerInputStreamMessageBodyHandler.java | 2 - .../ServerNumberMessageBodyHandler.java | 2 - .../serialisers/ServerPathBodyHandler.java | 2 - .../ServerPathPartBodyHandler.java | 2 - .../ServerStringMessageBodyHandler.java | 2 - 15 files changed, 33 insertions(+), 38 deletions(-) diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/response/ChunkedResponseTest.java b/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/response/ChunkedResponseTest.java index 1bd68e6a2d9bb..ae68349b887c2 100644 --- a/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/response/ChunkedResponseTest.java +++ b/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/response/ChunkedResponseTest.java @@ -7,14 +7,21 @@ import java.io.IOException; import java.io.OutputStream; import java.io.UncheckedIOException; +import java.lang.annotation.Annotation; import java.lang.reflect.Type; +import java.nio.charset.StandardCharsets; +import javax.annotation.Priority; import javax.ws.rs.GET; import javax.ws.rs.Path; +import javax.ws.rs.Priorities; import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.ext.Provider; -import org.jboss.resteasy.reactive.server.providers.serialisers.ServerStringMessageBodyHandler; +import org.jboss.resteasy.reactive.server.spi.ResteasyReactiveResourceInfo; +import org.jboss.resteasy.reactive.server.spi.ServerMessageBodyWriter; import org.jboss.resteasy.reactive.server.spi.ServerRequestContext; import org.jboss.shrinkwrap.api.asset.StringAsset; import org.junit.jupiter.api.Test; @@ -68,29 +75,39 @@ public String helloSmall() { } @Provider - public static class CustomStringMessageBodyWriter extends ServerStringMessageBodyHandler { + public static class CustomStringMessageBodyWriter implements ServerMessageBodyWriter { @Override - public void writeResponse(Object o, Type genericType, ServerRequestContext context) - throws WebApplicationException { + public boolean isWriteable(Class type, Type genericType, ResteasyReactiveResourceInfo target, MediaType mediaType) { + return true; + } - try (OutputStream stream = context.getOrCreateOutputStream()) { - stream.write(((String) o).getBytes()); - } catch (IOException e) { - throw new UncheckedIOException(e); - } + @Override + public void writeResponse(String o, Type genericType, ServerRequestContext context) throws WebApplicationException { + context.serverResponse().end(o); + } + + public boolean isWriteable(Class type, Type genericType, Annotation[] annotations, MediaType mediaType) { + return true; + } + + public void writeTo(String o, Class type, Type genericType, Annotation[] annotations, MediaType mediaType, + MultivaluedMap httpHeaders, OutputStream entityStream) + throws IOException, WebApplicationException { + entityStream.write(o.getBytes(StandardCharsets.UTF_8)); } } @Provider + @Priority(Priorities.USER + 1) // the spec says that when it comes to writers, higher number means higher priority... public static final class CustomStringMessageBodyWriter2 extends CustomStringMessageBodyWriter { @Override - public void writeResponse(Object o, Type genericType, ServerRequestContext context) + public void writeResponse(String o, Type genericType, ServerRequestContext context) throws WebApplicationException { try (OutputStream stream = context.getOrCreateOutputStream()) { - stream.write(((String) o).getBytes()); + stream.write(o.getBytes()); } catch (IOException e) { throw new UncheckedIOException(e); } diff --git a/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/core/Serialisers.java b/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/core/Serialisers.java index 3f0b755be1ab0..1f5020bae6a4b 100644 --- a/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/core/Serialisers.java +++ b/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/core/Serialisers.java @@ -151,7 +151,11 @@ public List> findBuildTimeWriters(Class entityType, Runt } } - return toMessageBodyWriters(findResourceWriters(writers, klass, produces, runtimeType)); + + var resourceWriters = findResourceWriters(writers, klass, produces, runtimeType); + // we must NOT sort here because the spec mentions that the writers closer to the requested java type are tried first + // and the list has already been built up in this way + return toMessageBodyWriters(resourceWriters); } protected List findResourceWriters(QuarkusMultivaluedMap, ResourceWriter> writers, Class klass, diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/ServerBooleanMessageBodyHandler.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/ServerBooleanMessageBodyHandler.java index 57c631c833a27..2be468dd0a7bf 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/ServerBooleanMessageBodyHandler.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/ServerBooleanMessageBodyHandler.java @@ -5,14 +5,12 @@ import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.MediaType; -import javax.ws.rs.ext.Provider; import org.jboss.resteasy.reactive.common.providers.serialisers.BooleanMessageBodyHandler; import org.jboss.resteasy.reactive.server.spi.ResteasyReactiveResourceInfo; import org.jboss.resteasy.reactive.server.spi.ServerMessageBodyReader; import org.jboss.resteasy.reactive.server.spi.ServerRequestContext; -@Provider public class ServerBooleanMessageBodyHandler extends BooleanMessageBodyHandler implements ServerMessageBodyReader { diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/ServerByteArrayMessageBodyHandler.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/ServerByteArrayMessageBodyHandler.java index 179b7ad9d40a1..1c1072159d824 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/ServerByteArrayMessageBodyHandler.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/ServerByteArrayMessageBodyHandler.java @@ -5,7 +5,6 @@ import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.MediaType; -import javax.ws.rs.ext.Provider; import org.jboss.resteasy.reactive.common.providers.serialisers.ByteArrayMessageBodyHandler; import org.jboss.resteasy.reactive.common.providers.serialisers.MessageReaderUtil; @@ -14,7 +13,6 @@ import org.jboss.resteasy.reactive.server.spi.ServerMessageBodyWriter; import org.jboss.resteasy.reactive.server.spi.ServerRequestContext; -@Provider public class ServerByteArrayMessageBodyHandler extends ByteArrayMessageBodyHandler implements ServerMessageBodyWriter, ServerMessageBodyReader { diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/ServerCharArrayMessageBodyHandler.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/ServerCharArrayMessageBodyHandler.java index d853248c25e62..ce54d00bc73d6 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/ServerCharArrayMessageBodyHandler.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/ServerCharArrayMessageBodyHandler.java @@ -5,7 +5,6 @@ import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.MediaType; -import javax.ws.rs.ext.Provider; import org.jboss.resteasy.reactive.common.providers.serialisers.CharArrayMessageBodyHandler; import org.jboss.resteasy.reactive.common.providers.serialisers.MessageReaderUtil; @@ -14,7 +13,6 @@ import org.jboss.resteasy.reactive.server.spi.ServerMessageBodyWriter; import org.jboss.resteasy.reactive.server.spi.ServerRequestContext; -@Provider public class ServerCharArrayMessageBodyHandler extends CharArrayMessageBodyHandler implements ServerMessageBodyWriter, ServerMessageBodyReader { diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/ServerCharacterMessageBodyHandler.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/ServerCharacterMessageBodyHandler.java index 5b7bbef52b761..e96f0c7d8dc7e 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/ServerCharacterMessageBodyHandler.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/ServerCharacterMessageBodyHandler.java @@ -5,14 +5,12 @@ import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.MediaType; -import javax.ws.rs.ext.Provider; import org.jboss.resteasy.reactive.common.providers.serialisers.CharacterMessageBodyHandler; import org.jboss.resteasy.reactive.server.spi.ResteasyReactiveResourceInfo; import org.jboss.resteasy.reactive.server.spi.ServerMessageBodyReader; import org.jboss.resteasy.reactive.server.spi.ServerRequestContext; -@Provider public class ServerCharacterMessageBodyHandler extends CharacterMessageBodyHandler implements ServerMessageBodyReader { diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/ServerDefaultTextPlainBodyHandler.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/ServerDefaultTextPlainBodyHandler.java index 9bf58af235dad..51779b09fe86e 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/ServerDefaultTextPlainBodyHandler.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/ServerDefaultTextPlainBodyHandler.java @@ -9,14 +9,12 @@ import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; -import javax.ws.rs.ext.Provider; import org.jboss.resteasy.reactive.common.providers.serialisers.DefaultTextPlainBodyHandler; import org.jboss.resteasy.reactive.server.spi.ResteasyReactiveResourceInfo; import org.jboss.resteasy.reactive.server.spi.ServerMessageBodyReader; import org.jboss.resteasy.reactive.server.spi.ServerRequestContext; -@Provider @Consumes("text/plain") public class ServerDefaultTextPlainBodyHandler extends DefaultTextPlainBodyHandler implements ServerMessageBodyReader { diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/ServerFileBodyHandler.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/ServerFileBodyHandler.java index 96a9280a5db8b..cb8fb60eca0a2 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/ServerFileBodyHandler.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/ServerFileBodyHandler.java @@ -8,14 +8,12 @@ import javax.ws.rs.Produces; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.MediaType; -import javax.ws.rs.ext.Provider; import org.jboss.resteasy.reactive.common.providers.serialisers.FileBodyHandler; import org.jboss.resteasy.reactive.server.spi.ResteasyReactiveResourceInfo; import org.jboss.resteasy.reactive.server.spi.ServerMessageBodyWriter; import org.jboss.resteasy.reactive.server.spi.ServerRequestContext; -@Provider @Produces("*/*") @Consumes("*/*") public class ServerFileBodyHandler extends FileBodyHandler implements ServerMessageBodyWriter { diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/ServerFilePartBodyHandler.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/ServerFilePartBodyHandler.java index ed08a6b5c1e28..6e820b21eab73 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/ServerFilePartBodyHandler.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/ServerFilePartBodyHandler.java @@ -7,7 +7,6 @@ import javax.ws.rs.Produces; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.MediaType; -import javax.ws.rs.ext.Provider; import org.jboss.resteasy.reactive.FilePart; import org.jboss.resteasy.reactive.common.providers.serialisers.FilePartBodyHandler; @@ -18,7 +17,6 @@ // TODO: this is very simplistic at the moment -@Provider @Produces("*/*") @Consumes("*/*") public class ServerFilePartBodyHandler extends FilePartBodyHandler implements ServerMessageBodyWriter { diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/ServerFormUrlEncodedProvider.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/ServerFormUrlEncodedProvider.java index 8816b553e3098..e5156e69a61c8 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/ServerFormUrlEncodedProvider.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/ServerFormUrlEncodedProvider.java @@ -11,7 +11,6 @@ import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MultivaluedMap; -import javax.ws.rs.ext.Provider; import org.jboss.resteasy.reactive.common.providers.serialisers.MapAsFormUrlEncodedProvider; import org.jboss.resteasy.reactive.common.providers.serialisers.MessageReaderUtil; @@ -25,7 +24,6 @@ * @version $Revision: 1 $ */ @SuppressWarnings("rawtypes") -@Provider @Produces("application/x-www-form-urlencoded") @Consumes("application/x-www-form-urlencoded") @ConstrainedTo(RuntimeType.CLIENT) diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/ServerInputStreamMessageBodyHandler.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/ServerInputStreamMessageBodyHandler.java index 279eea052b6b6..e425943db55d2 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/ServerInputStreamMessageBodyHandler.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/ServerInputStreamMessageBodyHandler.java @@ -7,7 +7,6 @@ import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.MediaType; -import javax.ws.rs.ext.Provider; import org.jboss.resteasy.reactive.common.providers.serialisers.InputStreamMessageBodyHandler; import org.jboss.resteasy.reactive.server.spi.ResteasyReactiveResourceInfo; @@ -15,7 +14,6 @@ import org.jboss.resteasy.reactive.server.spi.ServerMessageBodyWriter; import org.jboss.resteasy.reactive.server.spi.ServerRequestContext; -@Provider public class ServerInputStreamMessageBodyHandler extends InputStreamMessageBodyHandler implements ServerMessageBodyReader, ServerMessageBodyWriter { diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/ServerNumberMessageBodyHandler.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/ServerNumberMessageBodyHandler.java index 35819c4697228..260f7c985d808 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/ServerNumberMessageBodyHandler.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/ServerNumberMessageBodyHandler.java @@ -5,14 +5,12 @@ import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.MediaType; -import javax.ws.rs.ext.Provider; import org.jboss.resteasy.reactive.common.providers.serialisers.NumberMessageBodyHandler; import org.jboss.resteasy.reactive.server.spi.ResteasyReactiveResourceInfo; import org.jboss.resteasy.reactive.server.spi.ServerMessageBodyReader; import org.jboss.resteasy.reactive.server.spi.ServerRequestContext; -@Provider public class ServerNumberMessageBodyHandler extends NumberMessageBodyHandler implements ServerMessageBodyReader { diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/ServerPathBodyHandler.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/ServerPathBodyHandler.java index 7183a8c02d856..9978e13d19e60 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/ServerPathBodyHandler.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/ServerPathBodyHandler.java @@ -9,7 +9,6 @@ import javax.ws.rs.Produces; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.MediaType; -import javax.ws.rs.ext.Provider; import org.jboss.resteasy.reactive.common.providers.serialisers.PathBodyHandler; import org.jboss.resteasy.reactive.server.spi.ResteasyReactiveResourceInfo; @@ -17,7 +16,6 @@ import org.jboss.resteasy.reactive.server.spi.ServerMessageBodyWriter; import org.jboss.resteasy.reactive.server.spi.ServerRequestContext; -@Provider @Produces("*/*") public class ServerPathBodyHandler extends PathBodyHandler implements ServerMessageBodyWriter { diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/ServerPathPartBodyHandler.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/ServerPathPartBodyHandler.java index ff2cfcaa5f5cc..0e5fe867bef72 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/ServerPathPartBodyHandler.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/ServerPathPartBodyHandler.java @@ -9,7 +9,6 @@ import javax.ws.rs.Produces; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.MediaType; -import javax.ws.rs.ext.Provider; import org.jboss.resteasy.reactive.PathPart; import org.jboss.resteasy.reactive.common.providers.serialisers.PathPartBodyHandler; @@ -18,7 +17,6 @@ import org.jboss.resteasy.reactive.server.spi.ServerMessageBodyWriter; import org.jboss.resteasy.reactive.server.spi.ServerRequestContext; -@Provider @Produces("*/*") public class ServerPathPartBodyHandler extends PathPartBodyHandler implements ServerMessageBodyWriter { diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/ServerStringMessageBodyHandler.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/ServerStringMessageBodyHandler.java index f4dbf1898226d..45564ddd73973 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/ServerStringMessageBodyHandler.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/ServerStringMessageBodyHandler.java @@ -5,7 +5,6 @@ import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.MediaType; -import javax.ws.rs.ext.Provider; import org.jboss.resteasy.reactive.common.providers.serialisers.StringMessageBodyHandler; import org.jboss.resteasy.reactive.server.spi.ResteasyReactiveResourceInfo; @@ -13,7 +12,6 @@ import org.jboss.resteasy.reactive.server.spi.ServerMessageBodyWriter; import org.jboss.resteasy.reactive.server.spi.ServerRequestContext; -@Provider public class ServerStringMessageBodyHandler extends StringMessageBodyHandler implements ServerMessageBodyWriter, ServerMessageBodyReader { From c5b87cf365729d0ecfc60da5e415174978ae87a4 Mon Sep 17 00:00:00 2001 From: Matej Novotny Date: Mon, 10 Oct 2022 16:49:09 +0200 Subject: [PATCH 3/3] Rename affected methods and introduce their deprecated variants with original syntax to give users time to adapt --- .../lambda/runtime/AmazonLambdaRecorder.java | 8 ++--- .../arc/test/unused/UnusedExclusionTest.java | 2 +- .../io/quarkus/arc/runtime/BeanContainer.java | 36 +++++++++++++++++++ .../arc/runtime/BeanContainerImpl.java | 10 ++++++ .../security/runtime/ElytronRecorder.java | 2 +- .../FunqyCloudFunctionsBindingRecorder.java | 2 +- .../funqy/runtime/FunctionConstructor.java | 2 +- .../orm/runtime/HibernateOrmRecorder.java | 2 +- .../client/runtime/InfinispanRecorder.java | 2 +- .../runtime/QuarkusConstructorInjector.java | 4 +-- .../common/runtime/ArcBeanFactory.java | 2 +- .../runtime/ResteasyReactiveRecorder.java | 2 +- .../security/webauthn/WebAuthnRecorder.java | 6 ++-- .../runtime/SmallRyeGraphQLRecorder.java | 2 +- .../runtime/SmallRyeMetricsRecorder.java | 2 +- .../runtime/UndertowDeploymentRecorder.java | 8 ++--- .../security/HttpSecurityRecorder.java | 2 +- .../client/runtime/WebsocketCoreRecorder.java | 2 +- .../java/io/quarkus/arc/ArcContainer.java | 15 ++++++++ .../io/quarkus/arc/impl/ArcContainerImpl.java | 30 ++++++++++++++-- .../quarkus/extest/runtime/TestRecorder.java | 2 +- 21 files changed, 114 insertions(+), 29 deletions(-) diff --git a/extensions/amazon-lambda/runtime/src/main/java/io/quarkus/amazon/lambda/runtime/AmazonLambdaRecorder.java b/extensions/amazon-lambda/runtime/src/main/java/io/quarkus/amazon/lambda/runtime/AmazonLambdaRecorder.java index dbec82f28d10d..5d8ce207a88e1 100644 --- a/extensions/amazon-lambda/runtime/src/main/java/io/quarkus/amazon/lambda/runtime/AmazonLambdaRecorder.java +++ b/extensions/amazon-lambda/runtime/src/main/java/io/quarkus/amazon/lambda/runtime/AmazonLambdaRecorder.java @@ -77,11 +77,11 @@ public void setHandlerClass(Class> handler, BeanC */ public static void handle(InputStream inputStream, OutputStream outputStream, Context context) throws IOException { if (streamHandlerClass != null) { - RequestStreamHandler handler = beanContainer.instance(streamHandlerClass); + RequestStreamHandler handler = beanContainer.beanInstance(streamHandlerClass); handler.handleRequest(inputStream, outputStream, context); } else { Object request = objectReader.readValue(inputStream); - RequestHandler handler = beanContainer.instance(handlerClass); + RequestHandler handler = beanContainer.beanInstance(handlerClass); Object response = handler.handleRequest(request, context); objectWriter.writeValue(outputStream, response); } @@ -166,7 +166,7 @@ public void startPollLoop(ShutdownContext context, LaunchMode launchMode) { @Override protected Object processRequest(Object input, AmazonLambdaContext context) throws Exception { - RequestHandler handler = beanContainer.instance(handlerClass); + RequestHandler handler = beanContainer.beanInstance(handlerClass); return handler.handleRequest(input, context); } @@ -188,7 +188,7 @@ protected boolean isStream() { @Override protected void processRequest(InputStream input, OutputStream output, AmazonLambdaContext context) throws Exception { - RequestStreamHandler handler = beanContainer.instance(streamHandlerClass); + RequestStreamHandler handler = beanContainer.beanInstance(streamHandlerClass); handler.handleRequest(input, output, context); } diff --git a/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/unused/UnusedExclusionTest.java b/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/unused/UnusedExclusionTest.java index 3f81e738c8f6a..03a84facdf2dd 100644 --- a/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/unused/UnusedExclusionTest.java +++ b/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/unused/UnusedExclusionTest.java @@ -74,7 +74,7 @@ public static class TestRecorder { public void test(BeanContainer beanContainer) { // This should trigger the warning - Gama was removed - Gama gama = beanContainer.instance(Gama.class); + Gama gama = beanContainer.beanInstance(Gama.class); // Test that fallback was used - no injection was performed Assertions.assertNull(gama.beanManager); } diff --git a/extensions/arc/runtime/src/main/java/io/quarkus/arc/runtime/BeanContainer.java b/extensions/arc/runtime/src/main/java/io/quarkus/arc/runtime/BeanContainer.java index df187a9e0c94c..77dfa066f4e78 100644 --- a/extensions/arc/runtime/src/main/java/io/quarkus/arc/runtime/BeanContainer.java +++ b/extensions/arc/runtime/src/main/java/io/quarkus/arc/runtime/BeanContainer.java @@ -10,11 +10,33 @@ public interface BeanContainer { /** + * Returns a bean instance for given bean type and qualifiers. + *

+ * This method follows standard CDI rules meaning that if there are two or more eligible beans, an ambiguous + * dependency exception is thrown. + * Note that the method is allowed to return {@code null} if there is no matching bean which allows + * for fallback implementations. * * @param type * @param qualifiers * @return a bean instance or {@code null} if no matching bean is found */ + default T beanInstance(Class type, Annotation... qualifiers) { + return beanInstanceFactory(type, qualifiers).create().get(); + } + + /** + * This method is deprecated and will be removed in future versions. + * Use {@link #beanInstance(Class, Annotation...)} instead. + *

+ * As opposed to {@link #beanInstance(Class, Annotation...)}, this method does NOT follow CDI + * resolution rules and in case of ambiguous resolution performs a choice based on the class type parameter. + * + * @param type + * @param qualifiers + * @return a bean instance or {@code null} if no matching bean is found + */ + @Deprecated default T instance(Class type, Annotation... qualifiers) { return instanceFactory(type, qualifiers).create().get(); } @@ -31,6 +53,20 @@ default T instance(Class type, Annotation... qualifiers) { * @param qualifiers * @return a bean instance factory, never {@code null} */ + Factory beanInstanceFactory(Class type, Annotation... qualifiers); + + /** + * This method is deprecated and will be removed in future versions. + * Use {@link #beanInstanceFactory(Class, Annotation...)} instead. + *

+ * As opposed to {@link #beanInstanceFactory(Class, Annotation...)}, this method does NOT follow CDI + * resolution rules and in case of ambiguous resolution performs a choice based on the class type parameter. + * + * @param type + * @param qualifiers + * @return a bean instance factory, never {@code null} + */ + @Deprecated Factory instanceFactory(Class type, Annotation... qualifiers); /** diff --git a/extensions/arc/runtime/src/main/java/io/quarkus/arc/runtime/BeanContainerImpl.java b/extensions/arc/runtime/src/main/java/io/quarkus/arc/runtime/BeanContainerImpl.java index a2b2d46495c41..de4a28e5c11df 100644 --- a/extensions/arc/runtime/src/main/java/io/quarkus/arc/runtime/BeanContainerImpl.java +++ b/extensions/arc/runtime/src/main/java/io/quarkus/arc/runtime/BeanContainerImpl.java @@ -21,9 +21,19 @@ public BeanContainerImpl(ArcContainer container) { this.container = container; } + @Override + public Factory beanInstanceFactory(Class type, Annotation... qualifiers) { + Supplier> handleSupplier = container.beanInstanceSupplier(type, qualifiers); + return createFactory(handleSupplier, type, qualifiers); + } + @Override public Factory instanceFactory(Class type, Annotation... qualifiers) { Supplier> handleSupplier = container.instanceSupplier(type, qualifiers); + return createFactory(handleSupplier, type, qualifiers); + } + + private Factory createFactory(Supplier> handleSupplier, Class type, Annotation... qualifiers) { if (handleSupplier == null) { LOGGER.debugf( "No matching bean found for type %s and qualifiers %s. The bean might have been marked as unused and removed during build.", diff --git a/extensions/elytron-security/runtime/src/main/java/io/quarkus/elytron/security/runtime/ElytronRecorder.java b/extensions/elytron-security/runtime/src/main/java/io/quarkus/elytron/security/runtime/ElytronRecorder.java index 1285e779a7486..a2ebff71bc80e 100644 --- a/extensions/elytron-security/runtime/src/main/java/io/quarkus/elytron/security/runtime/ElytronRecorder.java +++ b/extensions/elytron-security/runtime/src/main/java/io/quarkus/elytron/security/runtime/ElytronRecorder.java @@ -31,7 +31,7 @@ public void runLoadTask(Runnable runnable) { } public void setDomainForIdentityProvider(BeanContainer bc, RuntimeValue domain) { - bc.instance(ElytronSecurityDomainManager.class).setDomain(domain.getValue()); + bc.beanInstance(ElytronSecurityDomainManager.class).setDomain(domain.getValue()); } /** diff --git a/extensions/funqy/funqy-google-cloud-functions/runtime/src/main/java/io/quarkus/funqy/gcp/functions/FunqyCloudFunctionsBindingRecorder.java b/extensions/funqy/funqy-google-cloud-functions/runtime/src/main/java/io/quarkus/funqy/gcp/functions/FunqyCloudFunctionsBindingRecorder.java index e643ac84819e4..4ae45066d22e2 100644 --- a/extensions/funqy/funqy-google-cloud-functions/runtime/src/main/java/io/quarkus/funqy/gcp/functions/FunqyCloudFunctionsBindingRecorder.java +++ b/extensions/funqy/funqy-google-cloud-functions/runtime/src/main/java/io/quarkus/funqy/gcp/functions/FunqyCloudFunctionsBindingRecorder.java @@ -32,7 +32,7 @@ public class FunqyCloudFunctionsBindingRecorder { public void init(BeanContainer bc) { beanContainer = bc; - objectMapper = beanContainer.instance(ObjectMapper.class); + objectMapper = beanContainer.beanInstance(ObjectMapper.class); for (FunctionInvoker invoker : FunctionRecorder.registry.invokers()) { if (invoker.hasInput()) { diff --git a/extensions/funqy/funqy-server-common/runtime/src/main/java/io/quarkus/funqy/runtime/FunctionConstructor.java b/extensions/funqy/funqy-server-common/runtime/src/main/java/io/quarkus/funqy/runtime/FunctionConstructor.java index d6f2f25386c6e..56abc399ebcb6 100644 --- a/extensions/funqy/funqy-server-common/runtime/src/main/java/io/quarkus/funqy/runtime/FunctionConstructor.java +++ b/extensions/funqy/funqy-server-common/runtime/src/main/java/io/quarkus/funqy/runtime/FunctionConstructor.java @@ -14,7 +14,7 @@ public FunctionConstructor(Class cls) { public T construct() { if (factory == null) - factory = CONTAINER.instanceFactory(cls); + factory = CONTAINER.beanInstanceFactory(cls); return factory.create().get(); } } diff --git a/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/HibernateOrmRecorder.java b/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/HibernateOrmRecorder.java index f5c22b8521543..31a74d5dabfad 100644 --- a/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/HibernateOrmRecorder.java +++ b/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/HibernateOrmRecorder.java @@ -92,7 +92,7 @@ public DataSourceTenantConnectionResolver get() { } public void startAllPersistenceUnits(BeanContainer beanContainer) { - beanContainer.instance(JPAConfig.class).startAll(); + beanContainer.beanInstance(JPAConfig.class).startAll(); } public Supplier sessionFactorySupplier(String persistenceUnitName) { diff --git a/extensions/infinispan-client/runtime/src/main/java/io/quarkus/infinispan/client/runtime/InfinispanRecorder.java b/extensions/infinispan-client/runtime/src/main/java/io/quarkus/infinispan/client/runtime/InfinispanRecorder.java index 49f4466156a26..5534f9658d78c 100644 --- a/extensions/infinispan-client/runtime/src/main/java/io/quarkus/infinispan/client/runtime/InfinispanRecorder.java +++ b/extensions/infinispan-client/runtime/src/main/java/io/quarkus/infinispan/client/runtime/InfinispanRecorder.java @@ -11,7 +11,7 @@ public class InfinispanRecorder { public BeanContainerListener configureInfinispan(@RelaxedValidation Properties properties) { return container -> { - InfinispanClientProducer instance = container.instance(InfinispanClientProducer.class); + InfinispanClientProducer instance = container.beanInstance(InfinispanClientProducer.class); instance.configure(properties); }; } diff --git a/extensions/resteasy-classic/resteasy-common/runtime/src/main/java/io/quarkus/resteasy/common/runtime/QuarkusConstructorInjector.java b/extensions/resteasy-classic/resteasy-common/runtime/src/main/java/io/quarkus/resteasy/common/runtime/QuarkusConstructorInjector.java index 218b5e6a3d6ef..df4ac2bf252a9 100644 --- a/extensions/resteasy-classic/resteasy-common/runtime/src/main/java/io/quarkus/resteasy/common/runtime/QuarkusConstructorInjector.java +++ b/extensions/resteasy-classic/resteasy-common/runtime/src/main/java/io/quarkus/resteasy/common/runtime/QuarkusConstructorInjector.java @@ -32,7 +32,7 @@ public Object construct(boolean unwrapAsync) { if (factory != null) { return factory.get().get(); } - factory = Arc.container().instanceSupplier(this.ctor.getDeclaringClass()); + factory = Arc.container().beanInstanceSupplier(this.ctor.getDeclaringClass()); if (factory == null) { return delegate.construct(unwrapAsync); } @@ -45,7 +45,7 @@ public Object construct(HttpRequest request, HttpResponse response, boolean unwr if (factory != null) { return factory.get().get(); } - factory = Arc.container().instanceSupplier(this.ctor.getDeclaringClass()); + factory = Arc.container().beanInstanceSupplier(this.ctor.getDeclaringClass()); if (factory == null) { return delegate.construct(request, response, unwrapAsync); } diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive-common/runtime/src/main/java/io/quarkus/resteasy/reactive/common/runtime/ArcBeanFactory.java b/extensions/resteasy-reactive/quarkus-resteasy-reactive-common/runtime/src/main/java/io/quarkus/resteasy/reactive/common/runtime/ArcBeanFactory.java index c44b8bb45458c..25656077526e0 100644 --- a/extensions/resteasy-reactive/quarkus-resteasy-reactive-common/runtime/src/main/java/io/quarkus/resteasy/reactive/common/runtime/ArcBeanFactory.java +++ b/extensions/resteasy-reactive/quarkus-resteasy-reactive-common/runtime/src/main/java/io/quarkus/resteasy/reactive/common/runtime/ArcBeanFactory.java @@ -12,7 +12,7 @@ public class ArcBeanFactory implements BeanFactory { public ArcBeanFactory(Class target, BeanContainer beanContainer) { targetClassName = target.getName(); - factory = beanContainer.instanceFactory(target); + factory = beanContainer.beanInstanceFactory(target); } @Override diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive/runtime/src/main/java/io/quarkus/resteasy/reactive/server/runtime/ResteasyReactiveRecorder.java b/extensions/resteasy-reactive/quarkus-resteasy-reactive/runtime/src/main/java/io/quarkus/resteasy/reactive/server/runtime/ResteasyReactiveRecorder.java index bff2c062d5962..b884ee5a741b8 100644 --- a/extensions/resteasy-reactive/quarkus-resteasy-reactive/runtime/src/main/java/io/quarkus/resteasy/reactive/server/runtime/ResteasyReactiveRecorder.java +++ b/extensions/resteasy-reactive/quarkus-resteasy-reactive/runtime/src/main/java/io/quarkus/resteasy/reactive/server/runtime/ResteasyReactiveRecorder.java @@ -133,7 +133,7 @@ public RuntimeValue createDeployment(DeploymentInfo info, } CurrentRequestManager - .setCurrentRequestInstance(new QuarkusCurrentRequest(beanContainer.instance(CurrentVertxRequest.class))); + .setCurrentRequestInstance(new QuarkusCurrentRequest(beanContainer.beanInstance(CurrentVertxRequest.class))); BlockingOperationSupport.setIoThreadDetector(new BlockingOperationSupport.IOThreadDetector() { @Override diff --git a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnRecorder.java b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnRecorder.java index ff44d478c63c8..72fe655cb61ba 100644 --- a/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnRecorder.java +++ b/extensions/security-webauthn/runtime/src/main/java/io/quarkus/security/webauthn/WebAuthnRecorder.java @@ -32,9 +32,9 @@ public WebAuthnRecorder(RuntimeValue httpConfiguration, Runti } public void setupRoutes(BeanContainer beanContainer, RuntimeValue routerValue, String prefix) { - WebAuthnSecurity security = beanContainer.instance(WebAuthnSecurity.class); - WebAuthnAuthenticationMechanism authMech = beanContainer.instance(WebAuthnAuthenticationMechanism.class); - IdentityProviderManager identityProviderManager = beanContainer.instance(IdentityProviderManager.class); + WebAuthnSecurity security = beanContainer.beanInstance(WebAuthnSecurity.class); + WebAuthnAuthenticationMechanism authMech = beanContainer.beanInstance(WebAuthnAuthenticationMechanism.class); + IdentityProviderManager identityProviderManager = beanContainer.beanInstance(IdentityProviderManager.class); WebAuthnController controller = new WebAuthnController(security, config.getValue(), identityProviderManager, authMech); Router router = routerValue.getValue(); BodyHandler bodyHandler = BodyHandler.create(); diff --git a/extensions/smallrye-graphql/runtime/src/main/java/io/quarkus/smallrye/graphql/runtime/SmallRyeGraphQLRecorder.java b/extensions/smallrye-graphql/runtime/src/main/java/io/quarkus/smallrye/graphql/runtime/SmallRyeGraphQLRecorder.java index 8e634b0de9892..048ac5e65d622 100644 --- a/extensions/smallrye-graphql/runtime/src/main/java/io/quarkus/smallrye/graphql/runtime/SmallRyeGraphQLRecorder.java +++ b/extensions/smallrye-graphql/runtime/src/main/java/io/quarkus/smallrye/graphql/runtime/SmallRyeGraphQLRecorder.java @@ -26,7 +26,7 @@ public class SmallRyeGraphQLRecorder { public RuntimeValue createExecutionService(BeanContainer beanContainer, Schema schema) { - GraphQLProducer graphQLProducer = beanContainer.instance(GraphQLProducer.class); + GraphQLProducer graphQLProducer = beanContainer.beanInstance(GraphQLProducer.class); GraphQLSchema graphQLSchema = graphQLProducer.initialize(schema); return new RuntimeValue<>(graphQLSchema != null); } diff --git a/extensions/smallrye-metrics/runtime/src/main/java/io/quarkus/smallrye/metrics/runtime/SmallRyeMetricsRecorder.java b/extensions/smallrye-metrics/runtime/src/main/java/io/quarkus/smallrye/metrics/runtime/SmallRyeMetricsRecorder.java index f087fc6124305..08966f4712840 100644 --- a/extensions/smallrye-metrics/runtime/src/main/java/io/quarkus/smallrye/metrics/runtime/SmallRyeMetricsRecorder.java +++ b/extensions/smallrye-metrics/runtime/src/main/java/io/quarkus/smallrye/metrics/runtime/SmallRyeMetricsRecorder.java @@ -194,7 +194,7 @@ public void createRegistries(BeanContainer container) { //HACK: registration is done via statics, but cleanup is done via pre destroy //however if the bean is not used it will not be created, so no cleanup will be done //we force bean creation here to make sure the container can restart correctly - container.instance(MetricRegistries.class).getApplicationRegistry(); + container.beanInstance(MetricRegistries.class).getApplicationRegistry(); } public void dropRegistriesAtShutdown(ShutdownContext shutdownContext) { diff --git a/extensions/undertow/runtime/src/main/java/io/quarkus/undertow/runtime/UndertowDeploymentRecorder.java b/extensions/undertow/runtime/src/main/java/io/quarkus/undertow/runtime/UndertowDeploymentRecorder.java index bcb9095df2ac4..0975c2cce33f4 100644 --- a/extensions/undertow/runtime/src/main/java/io/quarkus/undertow/runtime/UndertowDeploymentRecorder.java +++ b/extensions/undertow/runtime/src/main/java/io/quarkus/undertow/runtime/UndertowDeploymentRecorder.java @@ -252,7 +252,7 @@ public RuntimeValue registerServlet(RuntimeValue de InstanceFactory instanceFactory) throws Exception { InstanceFactory factory = instanceFactory != null ? instanceFactory - : new QuarkusInstanceFactory(beanContainer.instanceFactory(servletClass)); + : new QuarkusInstanceFactory(beanContainer.beanInstanceFactory(servletClass)); ServletInfo servletInfo = new ServletInfo(name, (Class) servletClass, factory); deploymentInfo.getValue().addServlet(servletInfo); @@ -304,7 +304,7 @@ public RuntimeValue registerFilter(RuntimeValue info InstanceFactory instanceFactory) throws Exception { InstanceFactory factory = instanceFactory != null ? instanceFactory - : new QuarkusInstanceFactory(beanContainer.instanceFactory(filterClass)); + : new QuarkusInstanceFactory(beanContainer.beanInstanceFactory(filterClass)); FilterInfo filterInfo = new FilterInfo(name, (Class) filterClass, factory); info.getValue().addFilter(filterInfo); filterInfo.setAsyncSupported(asyncSupported); @@ -329,7 +329,7 @@ public void registerListener(RuntimeValue info, Class listene info.getValue() .addListener(new ListenerInfo((Class) listenerClass, (InstanceFactory) new QuarkusInstanceFactory<>( - factory.instanceFactory(listenerClass)))); + factory.beanInstanceFactory(listenerClass)))); } public void addMimeMapping(RuntimeValue info, String extension, @@ -457,7 +457,7 @@ public DeploymentManager bootServletContainer(RuntimeValue info, info.getValue().setClassIntrospecter(new ClassIntrospecter() { @Override public InstanceFactory createInstanceFactory(Class clazz) throws NoSuchMethodException { - BeanContainer.Factory res = beanContainer.instanceFactory(clazz); + BeanContainer.Factory res = beanContainer.beanInstanceFactory(clazz); if (res == null) { return defaultVal.createInstanceFactory(clazz); } diff --git a/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/security/HttpSecurityRecorder.java b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/security/HttpSecurityRecorder.java index f4ca987fb85a2..053aa4542fcd9 100644 --- a/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/security/HttpSecurityRecorder.java +++ b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/security/HttpSecurityRecorder.java @@ -241,7 +241,7 @@ public BeanContainerListener initPermissions(HttpBuildTimeConfig permissions, return new BeanContainerListener() { @Override public void created(BeanContainer container) { - container.instance(PathMatchingHttpSecurityPolicy.class).init(permissions, policies); + container.beanInstance(PathMatchingHttpSecurityPolicy.class).init(permissions, policies); } }; } diff --git a/extensions/websockets/client/runtime/src/main/java/io/quarkus/websockets/client/runtime/WebsocketCoreRecorder.java b/extensions/websockets/client/runtime/src/main/java/io/quarkus/websockets/client/runtime/WebsocketCoreRecorder.java index 93ed683e37a61..ca321461c596d 100644 --- a/extensions/websockets/client/runtime/src/main/java/io/quarkus/websockets/client/runtime/WebsocketCoreRecorder.java +++ b/extensions/websockets/client/runtime/src/main/java/io/quarkus/websockets/client/runtime/WebsocketCoreRecorder.java @@ -125,7 +125,7 @@ public RuntimeValue createServerContainer(BeanContaine ServerWebSocketContainer container = serverContainerFactory.create(new ObjectIntrospecter() { @Override public ObjectFactory createInstanceFactory(Class clazz) { - BeanContainer.Factory factory = beanContainer.instanceFactory(clazz); + BeanContainer.Factory factory = beanContainer.beanInstanceFactory(clazz); return new ObjectFactory() { @Override public ObjectHandle createInstance() { diff --git a/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/ArcContainer.java b/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/ArcContainer.java index 6f778ca19e69a..19f49a9b2de57 100644 --- a/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/ArcContainer.java +++ b/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/ArcContainer.java @@ -99,6 +99,21 @@ public interface ArcContainer { * @param * @return */ + Supplier> beanInstanceSupplier(Class type, Annotation... qualifiers); + + /** + * This method is deprecated and will be removed in future versions. + * Use {@link #beanInstanceSupplier(Class, Annotation...)} instead. + *

+ * As opposed to {@link #beanInstanceSupplier(Class, Annotation...)}, this method does NOT follow CDI + * resolution rules and in case of ambiguous resolution performs a choice based on the class type parameter. + * + * @param type + * @param qualifiers + * @return + * @param + */ + @Deprecated Supplier> instanceSupplier(Class type, Annotation... qualifiers); /** diff --git a/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/ArcContainerImpl.java b/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/ArcContainerImpl.java index 94230917eb52c..3c88386ab5925 100644 --- a/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/ArcContainerImpl.java +++ b/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/ArcContainerImpl.java @@ -235,17 +235,41 @@ public InstanceHandle instance(Type type, Annotation... qualifiers) { } @SuppressWarnings("unchecked") + @Override + public Supplier> beanInstanceSupplier(Class type, Annotation... qualifiers) { + return createInstanceSupplier(false, type, qualifiers); + } + @Override public Supplier> instanceSupplier(Class type, Annotation... qualifiers) { + return createInstanceSupplier(true, type, qualifiers); + } + + private Supplier> createInstanceSupplier(boolean resolveAmbiguities, Class type, + Annotation... qualifiers) { if (qualifiers == null || qualifiers.length == 0) { qualifiers = new Annotation[] { Default.Literal.INSTANCE }; } Set> resolvedBeans = resolved.getValue(new Resolvable(type, qualifiers)); + Set> filteredBean = resolvedBeans; if (resolvedBeans.size() > 1) { - throw new AmbiguousResolutionException("Beans: " + resolvedBeans); + if (resolveAmbiguities) { + // this is non-standard CDI behavior that we momentarily keep to retain compatibility + // if there are multiple beans we look for an exact match + // this method is only called with the exact type required + // so ignoring subclasses is the correct behaviour + filteredBean = new HashSet<>(); + for (InjectableBean i : resolvedBeans) { + if (i.getBeanClass().equals(type)) { + filteredBean.add(i); + } + } + } else { + throw new AmbiguousResolutionException("Beans: " + resolvedBeans); + } } - InjectableBean bean = resolvedBeans.size() != 1 ? null - : (InjectableBean) resolvedBeans.iterator().next(); + InjectableBean bean = filteredBean.size() != 1 ? null + : (InjectableBean) filteredBean.iterator().next(); if (bean == null) { return null; } diff --git a/integration-tests/test-extension/extension/runtime/src/main/java/io/quarkus/extest/runtime/TestRecorder.java b/integration-tests/test-extension/extension/runtime/src/main/java/io/quarkus/extest/runtime/TestRecorder.java index d7f90b7c5eb84..ae6cf57794b9a 100644 --- a/integration-tests/test-extension/extension/runtime/src/main/java/io/quarkus/extest/runtime/TestRecorder.java +++ b/integration-tests/test-extension/extension/runtime/src/main/java/io/quarkus/extest/runtime/TestRecorder.java @@ -54,7 +54,7 @@ public void startRuntimeService(ShutdownContext shutdownContext, RuntimeValue