Skip to content

Commit

Permalink
Rest Reactive: align produces between client and server
Browse files Browse the repository at this point in the history
#fixes 16184
  • Loading branch information
michalszynkiewicz committed May 5, 2021
1 parent 2dfe0aa commit 16fd506
Show file tree
Hide file tree
Showing 8 changed files with 52 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,13 @@ public class ClientEndpointIndexer

private final String[] defaultProduces;
private final String[] defaultProducesNegotiated;
private final boolean smartDefaultProduces;

ClientEndpointIndexer(Builder builder, String defaultProduces) {
ClientEndpointIndexer(Builder builder, String defaultProduces, boolean smartDefaultProduces) {
super(builder);
this.defaultProduces = new String[] { defaultProduces };
this.defaultProducesNegotiated = new String[] { defaultProduces, MediaType.WILDCARD };
this.smartDefaultProduces = smartDefaultProduces;
}

public MaybeRestClientInterface createClientProxy(ClassInfo classInfo,
Expand Down Expand Up @@ -125,10 +127,14 @@ elementType, toClassName(paramType, currentClassInfo, actualEndpointInfo, index)

@Override
protected String[] applyAdditionalDefaults(Type nonAsyncReturnType) {
if (config.isSingleDefaultProduces()) {
return defaultProduces;
if (smartDefaultProduces) {
return super.applyAdditionalDefaults(nonAsyncReturnType);
} else {
return defaultProducesNegotiated;
if (config.isSingleDefaultProduces()) {
return defaultProduces;
} else {
return defaultProducesNegotiated;
}
}
}

Expand Down Expand Up @@ -166,15 +172,21 @@ public static class ClientIndexedParam extends IndexedParameter<ClientIndexedPar

public static final class Builder extends EndpointIndexer.Builder<ClientEndpointIndexer, Builder, ResourceMethod> {
private String defaultProduces = MediaType.TEXT_PLAIN;
private boolean smartDefaultProduces = true;

public Builder setDefaultProduces(String defaultProduces) {
this.defaultProduces = defaultProduces;
return this;
}

public Builder setSmartDefaultProduces(boolean smartDefaultProduces) {
this.smartDefaultProduces = smartDefaultProduces;
return this;
}

@Override
public ClientEndpointIndexer build() {
return new ClientEndpointIndexer(this, defaultProduces);
return new ClientEndpointIndexer(this, defaultProduces, smartDefaultProduces);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,8 @@ void setupClientProxies(JaxrsClientReactiveRecorder recorder,
BuildProducer<GeneratedClassBuildItem> generatedClassBuildItemBuildProducer,
BuildProducer<BytecodeTransformerBuildItem> bytecodeTransformerBuildItemBuildProducer,
List<RestClientDefaultProducesBuildItem> defaultConsumes,
List<RestClientDefaultConsumesBuildItem> defaultProduces) {
List<RestClientDefaultConsumesBuildItem> defaultProduces,
List<RestClientDisableSmartDefaultProduces> disableSmartDefaultProduces) {
String defaultConsumesType = defaultMediaType(defaultConsumes, MediaType.APPLICATION_OCTET_STREAM);
String defaultProducesType = defaultMediaType(defaultProduces, MediaType.TEXT_PLAIN);

Expand Down Expand Up @@ -191,6 +192,7 @@ void setupClientProxies(JaxrsClientReactiveRecorder recorder,
.setDefaultBlocking(applicationResultBuildItem.getResult().isBlocking())
.setHasRuntimeConverters(false)
.setDefaultProduces(defaultProducesType)
.setSmartDefaultProduces(disableSmartDefaultProduces.isEmpty())
.build();

Map<String, RuntimeValue<Function<WebTarget, ?>>> clientImplementations = new HashMap<>();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package io.quarkus.jaxrs.client.reactive.deployment;

import io.quarkus.builder.item.MultiBuildItem;

/**
* By default, RESTEasy Reactive uses text/plain content type for String values
* and application/json for everything else.
* MicroProfile Rest Client spec requires the implementations to always default to application/json.
* This build item disables the "smart" behavior of RESTEasy Reactive to comply to the spec
*/
public final class RestClientDisableSmartDefaultProduces extends MultiBuildItem {
}
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
import io.quarkus.jaxrs.client.reactive.deployment.JaxrsClientReactiveEnricherBuildItem;
import io.quarkus.jaxrs.client.reactive.deployment.RestClientDefaultConsumesBuildItem;
import io.quarkus.jaxrs.client.reactive.deployment.RestClientDefaultProducesBuildItem;
import io.quarkus.jaxrs.client.reactive.deployment.RestClientDisableSmartDefaultProduces;
import io.quarkus.rest.client.reactive.runtime.AnnotationRegisteredProviders;
import io.quarkus.rest.client.reactive.runtime.HeaderCapturingServerFilter;
import io.quarkus.rest.client.reactive.runtime.HeaderContainer;
Expand Down Expand Up @@ -98,9 +99,14 @@ ExtensionSslNativeSupportBuildItem activateSslNativeSupport() {

@BuildStep
void setUpDefaultMediaType(BuildProducer<RestClientDefaultConsumesBuildItem> consumes,
BuildProducer<RestClientDefaultProducesBuildItem> produces) {
BuildProducer<RestClientDefaultProducesBuildItem> produces,
BuildProducer<RestClientDisableSmartDefaultProduces> disableSmartProduces,
RestClientReactiveConfig config) {
consumes.produce(new RestClientDefaultConsumesBuildItem(MediaType.APPLICATION_JSON, 10));
produces.produce(new RestClientDefaultProducesBuildItem(MediaType.APPLICATION_JSON, 10));
if (config.disableSmartProduces) {
disableSmartProduces.produce(new RestClientDisableSmartDefaultProduces());
}
}

@BuildStep
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
import io.quarkus.arc.Arc;
import io.quarkus.test.QuarkusUnitTest;

public class BasicMpRestClientTest {
public class BasicRestClientTest {
@RegisterExtension
static final QuarkusUnitTest TEST = new QuarkusUnitTest()
.setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,13 @@
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

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

@RegisterRestClient(configKey = "hello2")
public interface HelloClient2 {
@POST
@Produces(MediaType.TEXT_PLAIN)
@Consumes(MediaType.TEXT_PLAIN)
@Path("/")
String echo(String name);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,18 @@
public class RestClientReactiveConfig {

/**
* Default scope for MicroProfile Rest Client. Use `javax.enterprise.context.Dependent` for spec-compliant behavior
* Default scope for Rest Client Reactive. Use `javax.enterprise.context.Dependent` for spec-compliant behavior
*/
@ConfigItem(name = "scope", defaultValue = "javax.enterprise.context.ApplicationScoped")
public String scope;

/**
* By default, RESTEasy Reactive uses text/plain content type for String values
* and application/json for everything else.
*
* MicroProfile Rest Client spec requires the implementations to always default to application/json.
* This build item disables the "smart" behavior of RESTEasy Reactive to comply to the spec
*/
@ConfigItem(name = "disable-smart-produces", defaultValue = "false")
public boolean disableSmartProduces;
}
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 @@
<io.quarkus.arquillian.copy-fields>true</io.quarkus.arquillian.copy-fields>
<quarkus.arc.remove-unused-beans>false</quarkus.arc.remove-unused-beans>
<quarkus.rest-client-reactive.scope>javax.enterprise.context.Dependent</quarkus.rest-client-reactive.scope>
<quarkus.rest-client-reactive.disable-smart-produces>true</quarkus.rest-client-reactive.disable-smart-produces>
<vertx.disableTCCL>true</vertx.disableTCCL>
<wiremock.server.port>${wiremock.server.port}</wiremock.server.port>
</systemPropertyVariables>
Expand Down

0 comments on commit 16fd506

Please sign in to comment.