Skip to content

Commit

Permalink
Make providers registered with @RegisterProvider CDI beans in reactiv…
Browse files Browse the repository at this point in the history
…e rest client

Fixes: #16540
  • Loading branch information
geoand committed Apr 21, 2021
1 parent e4f1d6b commit 4b58fa8
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 9 deletions.
@@ -1,5 +1,8 @@
package io.quarkus.rest.client.reactive.deployment;

import javax.ws.rs.client.ClientRequestFilter;
import javax.ws.rs.client.ClientResponseFilter;

import org.eclipse.microprofile.rest.client.annotation.ClientHeaderParam;
import org.eclipse.microprofile.rest.client.annotation.ClientHeaderParams;
import org.eclipse.microprofile.rest.client.annotation.RegisterClientHeaders;
Expand All @@ -14,6 +17,8 @@ public class DotNames {
public static final DotName CLIENT_HEADER_PARAM = DotName.createSimple(ClientHeaderParam.class.getName());
public static final DotName CLIENT_HEADER_PARAMS = DotName.createSimple(ClientHeaderParams.class.getName());
public static final DotName REGISTER_CLIENT_HEADERS = DotName.createSimple(RegisterClientHeaders.class.getName());
public static final DotName CLIENT_REQUEST_FILTER = DotName.createSimple(ClientRequestFilter.class.getName());
public static final DotName CLIENT_RESPONSE_FILTER = DotName.createSimple(ClientResponseFilter.class.getName());

private DotNames() {
}
Expand Down
Expand Up @@ -435,7 +435,7 @@ private AnnotationInstance[] extractAnnotations(AnnotationInstance groupAnnotati

private void addProvider(MethodCreator ctor, AssignableResultHandle target, IndexView index,
AnnotationInstance registerProvider) {
// if a registered provider is a cdi bean, it has to be reused
// if a registered provider is a CDI bean, it has to be reused
// take the name of the provider class from the annotation:
String providerClass = registerProvider.value().asString();

Expand All @@ -444,6 +444,14 @@ private void addProvider(MethodCreator ctor, AssignableResultHandle target, Inde
MethodDescriptor.ofMethod(BeanGrabber.class, "getBeanIfDefined", Object.class, Class.class),
ctor.loadClass(providerClass));

ClassInfo providerClassInfo;
if (registerProvider.target() != null) {
providerClassInfo = registerProvider.target().asClass();
} else {
// this is the case when the @RegisterProvider annotation is repeated
providerClassInfo = index.getClassByName(DotName.createSimple(providerClass));
}

// if bean != null, register the bean
BranchResult branchResult = ctor.ifNotNull(providerBean);
BytecodeCreator beanProviderAvailable = branchResult.trueBranch();
Expand All @@ -457,13 +465,19 @@ private void addProvider(MethodCreator ctor, AssignableResultHandle target, Inde

// else, create a new instance of the provider class
BytecodeCreator beanProviderNotAvailable = branchResult.falseBranch();
ResultHandle provider = beanProviderNotAvailable.newInstance(MethodDescriptor.ofConstructor(providerClass));
alteredTarget = beanProviderNotAvailable.invokeInterfaceMethod(
MethodDescriptor.ofMethod(Configurable.class, "register", Configurable.class, Object.class,
int.class),
target, provider,
beanProviderNotAvailable.load(registerProvider.valueWithDefault(index, "priority").asInt()));
beanProviderNotAvailable.assign(target, alteredTarget);
if ((providerClassInfo != null) && providerClassInfo.hasNoArgsConstructor()) { // if the filter has a no-args constructor, use it
ResultHandle provider = beanProviderNotAvailable.newInstance(MethodDescriptor.ofConstructor(providerClass));
alteredTarget = beanProviderNotAvailable.invokeInterfaceMethod(
MethodDescriptor.ofMethod(Configurable.class, "register", Configurable.class, Object.class,
int.class),
target, provider,
beanProviderNotAvailable.load(registerProvider.valueWithDefault(index, "priority").asInt()));
beanProviderNotAvailable.assign(target, alteredTarget);
} else { // the filter does not have a no-args constructor, so we can do nothing but fail
beanProviderNotAvailable.throwException(IllegalStateException.class,
"Provider " + providerClass + " must either be a CDI bean or have a no-args constructor");
}

}

}
@@ -1,11 +1,15 @@
package io.quarkus.rest.client.reactive.deployment;

import static io.quarkus.rest.client.reactive.deployment.DotNames.REGISTER_CLIENT_HEADERS;
import static io.quarkus.rest.client.reactive.deployment.DotNames.REGISTER_PROVIDER;
import static io.quarkus.rest.client.reactive.deployment.DotNames.REGISTER_PROVIDERS;
import static org.jboss.resteasy.reactive.common.processor.EndpointIndexer.CDI_WRAPPER_SUFFIX;
import static org.jboss.resteasy.reactive.common.processor.scanning.ResteasyReactiveScanner.BUILTIN_HTTP_ANNOTATIONS_TO_METHOD;

import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
Expand All @@ -27,6 +31,7 @@
import org.jboss.jandex.ClassInfo;
import org.jboss.jandex.CompositeIndex;
import org.jboss.jandex.DotName;
import org.jboss.jandex.IndexView;
import org.jboss.jandex.MethodInfo;
import org.jboss.jandex.Type;
import org.jboss.logging.Logger;
Expand Down Expand Up @@ -132,7 +137,7 @@ private void searchForJaxRsMethods(List<MethodInfo> listOfKnownMethods, ClassInf
@BuildStep
void registerHeaderFactoryBeans(CombinedIndexBuildItem index,
BuildProducer<AdditionalBeanBuildItem> additionalBeans) {
Collection<AnnotationInstance> annotations = index.getIndex().getAnnotations(DotNames.REGISTER_CLIENT_HEADERS);
Collection<AnnotationInstance> annotations = index.getIndex().getAnnotations(REGISTER_CLIENT_HEADERS);

for (AnnotationInstance registerClientHeaders : annotations) {
AnnotationValue value = registerClientHeaders.value();
Expand All @@ -146,6 +151,25 @@ void registerHeaderFactoryBeans(CombinedIndexBuildItem index,
}
}

@BuildStep
AdditionalBeanBuildItem registerProviderBeans(CombinedIndexBuildItem combinedIndex) {
IndexView index = combinedIndex.getIndex();
List<AnnotationInstance> allInstances = new ArrayList<>(index.getAnnotations(REGISTER_PROVIDER));
for (AnnotationInstance annotation : index.getAnnotations(REGISTER_PROVIDERS)) {
allInstances.addAll(Arrays.asList(annotation.value().asNestedArray()));
}
allInstances.addAll(index.getAnnotations(REGISTER_CLIENT_HEADERS));
AdditionalBeanBuildItem.Builder builder = AdditionalBeanBuildItem.builder().setUnremovable();
for (AnnotationInstance annotationInstance : allInstances) {
// Make sure all providers not annotated with @Provider but used in @RegisterProvider are registered as beans
AnnotationValue value = annotationInstance.value();
if (value != null) {
builder.addBeanClass(value.asClass().toString());
}
}
return builder.build();
}

@BuildStep
void addRestClientBeans(Capabilities capabilities,
CombinedIndexBuildItem combinedIndexBuildItem,
Expand Down
@@ -0,0 +1,12 @@
package io.quarkus.it.rest.client;

import javax.ws.rs.client.ClientRequestContext;
import javax.ws.rs.client.ClientRequestFilter;

public class DefaultCtorTestFilter implements ClientRequestFilter {

@Override
public void filter(ClientRequestContext requestContext) {
System.out.println(requestContext.getMethod());
}
}
@@ -0,0 +1,22 @@
package io.quarkus.it.rest.client;

import javax.ws.rs.client.ClientRequestContext;
import javax.ws.rs.client.ClientRequestFilter;

import com.fasterxml.jackson.databind.ObjectMapper;

public class NonDefaultCtorTestFilter implements ClientRequestFilter {

// used only to ensure that CDI injection works properly
private final ObjectMapper mapper;

public NonDefaultCtorTestFilter(ObjectMapper mapper) {
this.mapper = mapper;
}

@Override
public void filter(ClientRequestContext requestContext) {
mapper.getFactory();
System.out.println(requestContext.getUri());
}
}
Expand Up @@ -8,9 +8,13 @@
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

import org.eclipse.microprofile.rest.client.annotation.RegisterProvider;

import io.smallrye.mutiny.Uni;

@Path("")
@RegisterProvider(DefaultCtorTestFilter.class)
@RegisterProvider(NonDefaultCtorTestFilter.class)
public interface SimpleClient {
@POST
@Produces(MediaType.APPLICATION_JSON)
Expand Down

0 comments on commit 4b58fa8

Please sign in to comment.