Skip to content

Commit

Permalink
RestEasy Reactive client ApplicationScoped by default, added a note a…
Browse files Browse the repository at this point in the history
…bout the client to the resteasy-reactive doc
  • Loading branch information
michalszynkiewicz committed Mar 12, 2021
1 parent 3625df0 commit b468f7a
Show file tree
Hide file tree
Showing 7 changed files with 103 additions and 9 deletions.
16 changes: 16 additions & 0 deletions docs/src/main/asciidoc/resteasy-reactive.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -1812,3 +1812,19 @@ public class ResourceForApp1Only {
----

Please note that if a JAX-RS Application has been detected and the method `getClasses()` and/or `getSingletons()` has/have been overridden, Quarkus will ignore the build time conditions and consider only what has been defined in the JAX-RS Application.


== RESTEasy Reactive client
In addition to the Server side, RESTEasy Reactive comes with a new MicroProfile Rest Client implementation that is non-blocking at its core.

To use it, add the `quarkus-rest-client-microprofile` extension to your project.
The client can be used as described in https://quarkus.io/guides/rest-client[Using the REST Client guide] and specified in the https://download.eclipse.org/microprofile/microprofile-rest-client-1.4.1/microprofile-rest-client-1.4.1.html[MicroProfile Rest Client specification], with a few exceptions:

- the extension name
- the default scope of the client for the new extension is `@ApplicationScoped` while the `quarkus-rest-client` defaults to `@Dependent`
To change this behavior, set the `quarkus.rest.client.scope` property to the fully qualified scope name.
- it is not possible to set `HostnameVerifier` or `SSLContext`
- a few things that don't make sense for a non-blocking implementations, such as setting the `ExecutorService`, don't work

It is important to note that the `quarkus-rest-client` extension may not work properly with RESTEasy Reactive.

Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
import io.quarkus.resteasy.reactive.client.deployment.RestClientDefaultProducesBuildItem;
import io.quarkus.resteasy.reactive.client.microprofile.HeaderCapturingServerFilter;
import io.quarkus.resteasy.reactive.client.microprofile.HeaderContainer;
import io.quarkus.resteasy.reactive.client.microprofile.ReactiveResteasyMpClientConfig;
import io.quarkus.resteasy.reactive.client.microprofile.RestClientCDIDelegateBuilder;
import io.quarkus.resteasy.reactive.client.microprofile.recorder.RestClientRecorder;
import io.quarkus.resteasy.reactive.spi.ContainerRequestFilterBuildItem;
Expand Down Expand Up @@ -128,7 +129,8 @@ void registerHeaderFactoryBeans(CombinedIndexBuildItem index,
@BuildStep
void addRestClientBeans(Capabilities capabilities,
CombinedIndexBuildItem combinedIndexBuildItem,
BuildProducer<GeneratedBeanBuildItem> generatedBeans) {
BuildProducer<GeneratedBeanBuildItem> generatedBeans,
ReactiveResteasyMpClientConfig clientConfig) {

CompositeIndex index = CompositeIndex.create(combinedIndexBuildItem.getIndex());
Set<AnnotationInstance> registerRestClientAnnos = new HashSet<>(index.getAnnotations(REGISTER_REST_CLIENT));
Expand All @@ -154,7 +156,7 @@ void addRestClientBeans(Capabilities capabilities,
// CLASS LEVEL
final String configPrefix = computeConfigPrefix(jaxrsInterface.name(), registerRestClient);
final ScopeInfo scope = computeDefaultScope(capabilities, ConfigProvider.getConfig(), jaxrsInterface,
configPrefix);
configPrefix, clientConfig);
// add a scope annotation, e.g. @Singleton
classCreator.addAnnotation(scope.getDotName().toString());
classCreator.addAnnotation(RestClient.class);
Expand Down Expand Up @@ -261,11 +263,19 @@ private String computeConfigPrefix(DotName interfaceName, AnnotationInstance reg

private ScopeInfo computeDefaultScope(Capabilities capabilities, Config config,
ClassInfo restClientInterface,
String configPrefix) {
String configPrefix,
ReactiveResteasyMpClientConfig mpClientConfig) {
ScopeInfo scopeToUse = null;
final Optional<String> scopeConfig = config
.getOptionalValue(String.format(RestClientCDIDelegateBuilder.REST_SCOPE_FORMAT, configPrefix), String.class);

BuiltinScope globalDefaultScope = BuiltinScope.from(DotName.createSimple(mpClientConfig.scope));
if (globalDefaultScope == null) {
log.warnv("Unable to map the global rest client scope: '{}' to a scope. Using @ApplicationScoped",
mpClientConfig.scope);
globalDefaultScope = BuiltinScope.APPLICATION;
}

if (scopeConfig.isPresent()) {
final DotName scope = DotName.createSimple(scopeConfig.get());
final BuiltinScope builtinScope = BuiltinScope.from(scope);
Expand All @@ -278,9 +288,8 @@ private ScopeInfo computeDefaultScope(Capabilities capabilities, Config config,
}

if (scopeToUse == null) {
log.warn(String.format(
"Unsupported default scope %s provided for rest client %s. Defaulting to @Dependent.",
scope, restClientInterface.name()));
log.warnf("Unsupported default scope {} provided for rest client {}. Defaulting to {}",
scope, restClientInterface.name(), globalDefaultScope.getName());
scopeToUse = BuiltinScope.DEPENDENT.getInfo();
}
} else {
Expand All @@ -299,6 +308,6 @@ private ScopeInfo computeDefaultScope(Capabilities capabilities, Config config,
}

// Initialize a default @Dependent scope as per the spec
return scopeToUse != null ? scopeToUse : BuiltinScope.DEPENDENT.getInfo();
return scopeToUse != null ? scopeToUse : globalDefaultScope.getInfo();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,20 @@

import static org.assertj.core.api.Assertions.assertThat;

import java.net.MalformedURLException;
import java.util.Set;

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.BeanManager;
import javax.inject.Inject;

import org.eclipse.microprofile.rest.client.inject.RestClient;
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.arc.Arc;
import io.quarkus.test.QuarkusUnitTest;

public class BasicMpRestClientTest {
Expand All @@ -29,7 +34,15 @@ void shouldHello() {
}

@Test
void shouldHelloThroughInjectedClient() throws MalformedURLException {
void shouldHelloThroughInjectedClient() {
assertThat(testBean.helloViaInjectedClient("wor1d")).isEqualTo("hello, wor1d");
}

@Test
void shouldHaveApplicationScopeByDefault() {
BeanManager beanManager = Arc.container().beanManager();
Set<Bean<?>> beans = beanManager.getBeans(HelloClient2.class, RestClient.LITERAL);
Bean<?> resolvedBean = beanManager.resolve(beans);
assertThat(resolvedBean.getScope()).isEqualTo(ApplicationScoped.class);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package io.quarkus.resteasy.reactive.client;

import static org.assertj.core.api.Assertions.assertThat;

import java.util.Set;

import javax.enterprise.context.Dependent;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.BeanManager;

import org.eclipse.microprofile.rest.client.inject.RestClient;
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.arc.Arc;
import io.quarkus.test.QuarkusUnitTest;

public class MpRestClientScopeOverrideTest {
@RegisterExtension
static final QuarkusUnitTest TEST = new QuarkusUnitTest()
.setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class)
.addClasses(HelloClient2.class))
.withConfigurationResource("dependent-test-application.properties");

@RestClient
HelloClient2 client;

@Test
void shouldHaveDependentScope() {
BeanManager beanManager = Arc.container().beanManager();
Set<Bean<?>> beans = beanManager.getBeans(HelloClient2.class, RestClient.LITERAL);
Bean<?> resolvedBean = beanManager.resolve(beans);
assertThat(resolvedBean.getScope()).isEqualTo(Dependent.class);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
hello2/mp-rest/url=http://localhost:${quarkus.http.test-port:8081}/hello

quarkus.rest-client.scope=javax.enterprise.context.Dependent
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package io.quarkus.resteasy.reactive.client.microprofile;

import io.quarkus.runtime.annotations.ConfigItem;
import io.quarkus.runtime.annotations.ConfigPhase;
import io.quarkus.runtime.annotations.ConfigRoot;

@ConfigRoot(phase = ConfigPhase.BUILD_TIME, name = "rest-client")
public class ReactiveResteasyMpClientConfig {

/**
* Default scope for MicroProfile Rest Client. Use `javax.enterprise.context.Dependent` for spec-compliant behavior
*/
@ConfigItem(name = "scope", defaultValue = "javax.enterprise.context.ApplicationScoped")
public String scope;
}
1 change: 1 addition & 0 deletions tcks/microprofile-rest-client-reactive/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
<quarkus.arc.remove-unused-beans>false</quarkus.arc.remove-unused-beans>
<io.quarkus.arquillian.copy-fields>true</io.quarkus.arquillian.copy-fields>
<wiremock.server.port>${wiremock.server.port}</wiremock.server.port>
<quarkus.rest-client.scope>javax.enterprise.context.Dependent</quarkus.rest-client.scope>
</systemPropertyVariables>
<!-- This workaround allows us to run a single test using
the "test" system property -->
Expand Down

0 comments on commit b468f7a

Please sign in to comment.