diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive-jackson-common/deployment/src/main/java/io/quarkus/resteasy/reactive/jackson/deployment/processor/ResteasyReactiveJacksonProviderDefinedBuildItem.java b/extensions/resteasy-reactive/quarkus-resteasy-reactive-jackson-common/deployment/src/main/java/io/quarkus/resteasy/reactive/jackson/deployment/processor/ResteasyReactiveJacksonProviderDefinedBuildItem.java deleted file mode 100644 index bab510942c126..0000000000000 --- a/extensions/resteasy-reactive/quarkus-resteasy-reactive-jackson-common/deployment/src/main/java/io/quarkus/resteasy/reactive/jackson/deployment/processor/ResteasyReactiveJacksonProviderDefinedBuildItem.java +++ /dev/null @@ -1,11 +0,0 @@ -package io.quarkus.resteasy.reactive.jackson.deployment.processor; - -import io.quarkus.builder.item.MultiBuildItem; - -/** - * A BuildItem to mark that the server side jackson provider is defined. - * If not "emitted" by any of the processors, the reactive rest client (if used) will add its own jackson provider - */ -public final class ResteasyReactiveJacksonProviderDefinedBuildItem extends MultiBuildItem { - -} diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive-jackson/deployment/src/main/java/io/quarkus/resteasy/reactive/jackson/deployment/processor/ResteasyReactiveJacksonProcessor.java b/extensions/resteasy-reactive/quarkus-resteasy-reactive-jackson/deployment/src/main/java/io/quarkus/resteasy/reactive/jackson/deployment/processor/ResteasyReactiveJacksonProcessor.java index c133d6a33f444..7f0cdfce4cfd8 100644 --- a/extensions/resteasy-reactive/quarkus-resteasy-reactive-jackson/deployment/src/main/java/io/quarkus/resteasy/reactive/jackson/deployment/processor/ResteasyReactiveJacksonProcessor.java +++ b/extensions/resteasy-reactive/quarkus-resteasy-reactive-jackson/deployment/src/main/java/io/quarkus/resteasy/reactive/jackson/deployment/processor/ResteasyReactiveJacksonProcessor.java @@ -94,11 +94,6 @@ ServerDefaultProducesHandlerBuildItem jsonDefault() { return ServerDefaultProducesHandlerBuildItem.json(); } - @BuildStep - ResteasyReactiveJacksonProviderDefinedBuildItem jacksonRegistered() { - return new ResteasyReactiveJacksonProviderDefinedBuildItem(); - } - @BuildStep ExceptionMapperBuildItem exceptionMappers() { return new ExceptionMapperBuildItem(DefaultMismatchedInputException.class.getName(), diff --git a/extensions/resteasy-reactive/rest-client-reactive-jackson/deployment/pom.xml b/extensions/resteasy-reactive/rest-client-reactive-jackson/deployment/pom.xml index 098e55811abe1..dcc31e57ff7d5 100644 --- a/extensions/resteasy-reactive/rest-client-reactive-jackson/deployment/pom.xml +++ b/extensions/resteasy-reactive/rest-client-reactive-jackson/deployment/pom.xml @@ -45,6 +45,11 @@ assertj-core test + + com.github.tomakehurst + wiremock-jre8-standalone + test + diff --git a/extensions/resteasy-reactive/rest-client-reactive-jackson/deployment/src/main/java/io/quarkus/rest/client/reactive/jackson/deployment/RestClientReactiveJacksonProcessor.java b/extensions/resteasy-reactive/rest-client-reactive-jackson/deployment/src/main/java/io/quarkus/rest/client/reactive/jackson/deployment/RestClientReactiveJacksonProcessor.java index e057f19afa33e..bf38043457c3c 100644 --- a/extensions/resteasy-reactive/rest-client-reactive-jackson/deployment/src/main/java/io/quarkus/rest/client/reactive/jackson/deployment/RestClientReactiveJacksonProcessor.java +++ b/extensions/resteasy-reactive/rest-client-reactive-jackson/deployment/src/main/java/io/quarkus/rest/client/reactive/jackson/deployment/RestClientReactiveJacksonProcessor.java @@ -15,7 +15,6 @@ import io.quarkus.deployment.builditem.FeatureBuildItem; import io.quarkus.rest.client.reactive.jackson.runtime.serialisers.ClientJacksonMessageBodyReader; import io.quarkus.rest.client.reactive.jackson.runtime.serialisers.ClientJacksonMessageBodyWriter; -import io.quarkus.resteasy.reactive.jackson.deployment.processor.ResteasyReactiveJacksonProviderDefinedBuildItem; import io.quarkus.resteasy.reactive.jackson.runtime.serialisers.vertx.VertxJsonArrayBasicMessageBodyReader; import io.quarkus.resteasy.reactive.jackson.runtime.serialisers.vertx.VertxJsonArrayBasicMessageBodyWriter; import io.quarkus.resteasy.reactive.jackson.runtime.serialisers.vertx.VertxJsonObjectBasicMessageBodyReader; @@ -38,13 +37,9 @@ void feature(BuildProducer features) { @BuildStep void additionalProviders( - List jacksonProviderDefined, BuildProducer additionalBean, BuildProducer additionalReaders, BuildProducer additionalWriters) { - if (!jacksonProviderDefined.isEmpty()) { - return; - } // make these beans to they can get instantiated with the Quarkus CDI configured Jsonb object additionalBean.produce(AdditionalBeanBuildItem.builder() .addBeanClass(ClientJacksonMessageBodyReader.class.getName()) diff --git a/extensions/resteasy-reactive/rest-client-reactive-jackson/deployment/src/test/java/io/quarkus/rest/client/reactive/jackson/test/ClientWithCustomObjectMapperTest.java b/extensions/resteasy-reactive/rest-client-reactive-jackson/deployment/src/test/java/io/quarkus/rest/client/reactive/jackson/test/ClientWithCustomObjectMapperTest.java new file mode 100644 index 0000000000000..879cbabb298b8 --- /dev/null +++ b/extensions/resteasy-reactive/rest-client-reactive-jackson/deployment/src/test/java/io/quarkus/rest/client/reactive/jackson/test/ClientWithCustomObjectMapperTest.java @@ -0,0 +1,141 @@ +package io.quarkus.rest.client.reactive.jackson.test; + +import static com.github.tomakehurst.wiremock.client.WireMock.okJson; +import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Objects; + +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 javax.ws.rs.ext.ContextResolver; + +import org.jboss.resteasy.reactive.ClientWebApplicationException; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.github.tomakehurst.wiremock.WireMockServer; +import com.github.tomakehurst.wiremock.client.WireMock; + +import io.quarkus.rest.client.reactive.runtime.RestClientBuilderImpl; +import io.quarkus.test.QuarkusUnitTest; +import io.smallrye.mutiny.Uni; + +public class ClientWithCustomObjectMapperTest { + + @RegisterExtension + static final QuarkusUnitTest TEST = new QuarkusUnitTest(); + + MyClient clientAllowsUnknown; + MyClient clientDisallowsUnknown; + WireMockServer wireMockServer; + + @BeforeEach + public void setUp() throws MalformedURLException { + wireMockServer = new WireMockServer(options().port(20001)); + wireMockServer.start(); + + clientAllowsUnknown = new RestClientBuilderImpl() + .baseUrl(new URL(wireMockServer.baseUrl())) + .register(ClientObjectMapperUnknown.class) + .build(MyClient.class); + + clientDisallowsUnknown = new RestClientBuilderImpl() + .baseUrl(new URL(wireMockServer.baseUrl())) + .register(ClientObjectMapperNoUnknown.class) + .build(MyClient.class); + } + + @AfterEach + public void tearDown() { + wireMockServer.stop(); + } + + @Test + void testCustomObjectMappersShouldBeUsed() { + var json = "{ \"value\": \"someValue\", \"secondValue\": \"toBeIgnored\" }"; + wireMockServer.stubFor( + WireMock.get(WireMock.urlMatching("/get")) + .willReturn(okJson(json))); + + // FAIL_ON_UNKNOWN_PROPERTIES disabled + assertThat(clientAllowsUnknown.get().await().indefinitely()) + .isEqualTo(new Request("someValue")); + + // FAIL_ON_UNKNOWN_PROPERTIES enabled + assertThatThrownBy(() -> clientDisallowsUnknown.get().await().indefinitely()) + .isInstanceOf(ClientWebApplicationException.class); + } + + @Path("/get") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public interface MyClient { + @GET + Uni get(); + } + + public static class Request { + private String value; + + public Request() { + + } + + public Request(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + Request request = (Request) o; + return Objects.equals(value, request.value); + } + + @Override + public int hashCode() { + return Objects.hash(value); + } + } + + public static class ClientObjectMapperUnknown implements ContextResolver { + @Override + public ObjectMapper getContext(Class type) { + return new ObjectMapper() + .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES) + .disable(SerializationFeature.FAIL_ON_EMPTY_BEANS); + } + } + + public static class ClientObjectMapperNoUnknown implements ContextResolver { + @Override + public ObjectMapper getContext(Class type) { + return new ObjectMapper() + .enable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES) + .enable(SerializationFeature.FAIL_ON_EMPTY_BEANS); + } + } +} diff --git a/extensions/resteasy-reactive/rest-client-reactive-jackson/runtime/src/main/java/io/quarkus/rest/client/reactive/jackson/runtime/serialisers/ClientJacksonMessageBodyReader.java b/extensions/resteasy-reactive/rest-client-reactive-jackson/runtime/src/main/java/io/quarkus/rest/client/reactive/jackson/runtime/serialisers/ClientJacksonMessageBodyReader.java index 662a9a77ee378..9e13462d4d04b 100644 --- a/extensions/resteasy-reactive/rest-client-reactive-jackson/runtime/src/main/java/io/quarkus/rest/client/reactive/jackson/runtime/serialisers/ClientJacksonMessageBodyReader.java +++ b/extensions/resteasy-reactive/rest-client-reactive-jackson/runtime/src/main/java/io/quarkus/rest/client/reactive/jackson/runtime/serialisers/ClientJacksonMessageBodyReader.java @@ -14,7 +14,6 @@ import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.Response; -import org.jboss.resteasy.reactive.ClientWebApplicationException; import org.jboss.resteasy.reactive.client.impl.RestClientRequestContext; import org.jboss.resteasy.reactive.client.spi.ClientRestHandler; import org.jboss.resteasy.reactive.server.jackson.JacksonBasicMessageBodyReader; @@ -40,7 +39,7 @@ public Object readFrom(Class type, Type genericType, Annotation[] annota try { return super.readFrom(type, genericType, annotations, mediaType, httpHeaders, entityStream); } catch (StreamReadException | DatabindException e) { - throw new ClientWebApplicationException(e, Response.Status.BAD_REQUEST); + throw new WebApplicationException(e, Response.Status.BAD_REQUEST); } }