Skip to content

Commit

Permalink
Merge pull request #22853 from Ladicek/copy-interface-annotations-res…
Browse files Browse the repository at this point in the history
…t-client-reactive

Copy RestClient interface annotations to generated class
  • Loading branch information
michalszynkiewicz authored Jan 17, 2022
2 parents 3089ef9 + 0e4e88a commit 0362cd7
Show file tree
Hide file tree
Showing 6 changed files with 86 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package io.quarkus.rest.client.reactive.deployment;

import static io.quarkus.arc.processor.MethodDescriptors.MAP_PUT;
import static io.quarkus.rest.client.reactive.deployment.DotNames.CLIENT_HEADER_PARAM;
import static io.quarkus.rest.client.reactive.deployment.DotNames.CLIENT_HEADER_PARAMS;
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;
Expand Down Expand Up @@ -45,6 +47,7 @@
import org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames;

import io.quarkus.arc.deployment.AdditionalBeanBuildItem;
import io.quarkus.arc.deployment.CustomScopeAnnotationsBuildItem;
import io.quarkus.arc.deployment.GeneratedBeanBuildItem;
import io.quarkus.arc.deployment.GeneratedBeanGizmoAdaptor;
import io.quarkus.arc.deployment.UnremovableBeanBuildItem;
Expand Down Expand Up @@ -94,6 +97,14 @@ class RestClientReactiveProcessor {
private static final String DISABLE_SMART_PRODUCES_QUARKUS = "quarkus.rest-client.disable-smart-produces";
private static final String KOTLIN_INTERFACE_DEFAULT_IMPL_SUFFIX = "$DefaultImpls";

private static final Set<DotName> SKIP_COPYING_ANNOTATIONS_TO_GENERATED_CLASS = Set.of(
REGISTER_REST_CLIENT,
REGISTER_PROVIDER,
REGISTER_PROVIDERS,
CLIENT_HEADER_PARAM,
CLIENT_HEADER_PARAMS,
REGISTER_CLIENT_HEADERS);

@BuildStep
void announceFeature(BuildProducer<FeatureBuildItem> features) {
features.produce(new FeatureBuildItem(Feature.REST_CLIENT_REACTIVE));
Expand Down Expand Up @@ -331,6 +342,7 @@ AdditionalBeanBuildItem registerProviderBeans(CombinedIndexBuildItem combinedInd
@Record(ExecutionTime.STATIC_INIT)
void addRestClientBeans(Capabilities capabilities,
CombinedIndexBuildItem combinedIndexBuildItem,
CustomScopeAnnotationsBuildItem scopes,
BuildProducer<GeneratedBeanBuildItem> generatedBeans,
RestClientReactiveConfig clientConfig,
RestClientRecorder recorder) {
Expand Down Expand Up @@ -389,6 +401,19 @@ void addRestClientBeans(Capabilities capabilities,
classCreator.addAnnotation(Typed.class.getName(), RetentionPolicy.RUNTIME)
.addValue("value", new org.objectweb.asm.Type[] { asmType });

for (AnnotationInstance annotation : jaxrsInterface.classAnnotations()) {
if (SKIP_COPYING_ANNOTATIONS_TO_GENERATED_CLASS.contains(annotation.name())) {
continue;
}

// scope annotation is added to the generated class already, see above
if (scopes.isScopeIn(Set.of(annotation))) {
continue;
}

classCreator.addAnnotation(annotation);
}

// CONSTRUCTOR:

MethodCreator constructor = classCreator
Expand Down Expand Up @@ -525,7 +550,7 @@ private ScopeInfo computeDefaultScope(Capabilities capabilities, Config config,
if (scopeToUse == null) {
log.warnf("Unsupported default scope {} provided for rest client {}. Defaulting to {}",
scope, restClientInterface.name(), globalDefaultScope.getName());
scopeToUse = BuiltinScope.DEPENDENT.getInfo();
scopeToUse = globalDefaultScope.getInfo();
}
} else {
final Set<DotName> annotations = restClientInterface.annotations().keySet();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

import org.jboss.logging.Logger;

import io.quarkus.arc.NoClassInterceptors;

public abstract class RestClientReactiveCDIWrapperBase<T extends Closeable> implements Closeable {
private static final Logger log = Logger.getLogger(RestClientReactiveCDIWrapperBase.class);

Expand All @@ -17,11 +19,13 @@ public RestClientReactiveCDIWrapperBase(Class<T> jaxrsInterface, String baseUriF
}

@Override
@NoClassInterceptors
public void close() throws IOException {
delegate.close();
}

@PreDestroy
@NoClassInterceptors
public void destroy() {
try {
close();
Expand All @@ -32,6 +36,7 @@ public void destroy() {

// used by generated code
@SuppressWarnings("unused")
@NoClassInterceptors
public Object getDelegate() {
return delegate;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,11 @@ void forEachMethod(ClassInfo clazz, Consumer<MethodInfo> action) {
// synthetic methods can't be intercepted
continue;
}
if (annotationStore.hasAnnotation(method, io.quarkus.arc.processor.DotNames.NO_CLASS_INTERCEPTORS)
&& !annotationStore.hasAnyAnnotation(method, DotNames.FT_ANNOTATIONS)) {
// methods annotated @NoClassInterceptors and not annotated with an interceptor binding are not intercepted
continue;
}

action.accept(method);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ public class ClientCallingResource {
@RestClient
FaultToleranceClient faultToleranceClient;

@RestClient
FaultToleranceOnInterfaceClient faultToleranceOnInterfaceClient;

@Inject
InMemorySpanExporter inMemorySpanExporter;

Expand Down Expand Up @@ -139,6 +142,16 @@ void init(@Observes Router router) {
router.route("/call-with-fault-tolerance").blockingHandler(rc -> {
rc.end(faultToleranceClient.helloWithFallback());
});

router.route("/call-with-fault-tolerance-on-interface").blockingHandler(rc -> {
String exception = "";
try {
faultToleranceOnInterfaceClient.hello();
} catch (Exception e) {
exception = e.getClass().getSimpleName();
}
rc.end(exception);
});
}

private Future<Void> success(RoutingContext rc, String body) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package io.quarkus.it.rest.client.main;

import java.time.temporal.ChronoUnit;

import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

import org.eclipse.microprofile.faulttolerance.CircuitBreaker;
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;

@Path("/unprocessable")
@RegisterRestClient(configKey = "w-fault-tolerance")
@CircuitBreaker(requestVolumeThreshold = 2, delay = 1, delayUnit = ChronoUnit.MINUTES)
public interface FaultToleranceOnInterfaceClient {
@GET
@Produces(MediaType.TEXT_PLAIN)
@Consumes(MediaType.TEXT_PLAIN)
String hello();
}
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,21 @@ void shouldInterceptDefaultMethod() {
.body(equalTo("Hello fallback!"));
}

@Test
void shouldApplyInterfaceLevelInterceptorBinding() {
for (int i = 0; i < 2; i++) {
RestAssured.with().body(baseUrl).post("/call-with-fault-tolerance-on-interface")
.then()
.statusCode(200)
.body(equalTo("ClientWebApplicationException"));
}

RestAssured.with().body(baseUrl).post("/call-with-fault-tolerance-on-interface")
.then()
.statusCode(200)
.body(equalTo("CircuitBreakerOpenException"));
}

@Test
void shouldCreateClientSpans() {
// Reset captured traces
Expand Down

0 comments on commit 0362cd7

Please sign in to comment.