diff --git a/bom/deployment/pom.xml b/bom/deployment/pom.xml
index 3b72d5afc0557..234529c3bc892 100644
--- a/bom/deployment/pom.xml
+++ b/bom/deployment/pom.xml
@@ -236,6 +236,21 @@
quarkus-rest-client-deployment
${project.version}
+
+ io.quarkus
+ quarkus-rest-client-jackson-deployment
+ ${project.version}
+
+
+ io.quarkus
+ quarkus-rest-client-jaxb-deployment
+ ${project.version}
+
+
+ io.quarkus
+ quarkus-rest-client-jsonb-deployment
+ ${project.version}
+
io.quarkus
quarkus-jaeger-deployment
diff --git a/bom/runtime/pom.xml b/bom/runtime/pom.xml
index d3c82401b67c3..10d434167fed5 100644
--- a/bom/runtime/pom.xml
+++ b/bom/runtime/pom.xml
@@ -560,6 +560,21 @@
quarkus-rest-client
${project.version}
+
+ io.quarkus
+ quarkus-rest-client-jackson
+ ${project.version}
+
+
+ io.quarkus
+ quarkus-rest-client-jaxb
+ ${project.version}
+
+
+ io.quarkus
+ quarkus-rest-client-jsonb
+ ${project.version}
+
io.quarkus
quarkus-resteasy-common
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/Capabilities.java b/core/deployment/src/main/java/io/quarkus/deployment/Capabilities.java
index 5e75521e1d3f9..62c05858864a1 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/Capabilities.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/Capabilities.java
@@ -15,6 +15,8 @@ public final class Capabilities extends SimpleBuildItem {
public static final String TRANSACTIONS = "io.quarkus.transactions";
public static final String JACKSON = "io.quarkus.jackson";
public static final String JSONB = "io.quarkus.jsonb";
+ public static final String REST_JACKSON = "io.quarkus.rest.jackson";
+ public static final String REST_JSONB = "io.quarkus.rest.jsonb";
public static final String RESTEASY_JSON_EXTENSION = "io.quarkus.resteasy-json";
public static final String RESTEASY = "io.quarkus.resteasy";
public static final String JWT = "io.quarkus.jwt";
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/builditem/FeatureBuildItem.java b/core/deployment/src/main/java/io/quarkus/deployment/builditem/FeatureBuildItem.java
index f43795633f15b..92da1114320c8 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/builditem/FeatureBuildItem.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/builditem/FeatureBuildItem.java
@@ -62,6 +62,9 @@ public final class FeatureBuildItem extends MultiBuildItem {
public static final String RESTEASY_MUTINY = "resteasy-mutiny";
public static final String RESTEASY_QUTE = "resteasy-qute";
public static final String REST_CLIENT = "rest-client";
+ public static final String REST_CLIENT_JACKSON = "rest-client-jackson";
+ public static final String REST_CLIENT_JAXB = "rest-client-jaxb";
+ public static final String REST_CLIENT_JSONB = "rest-client-jsonb";
public static final String SCALA = "scala";
public static final String SCHEDULER = "scheduler";
public static final String SECURITY = "security";
diff --git a/extensions/pom.xml b/extensions/pom.xml
index 4d6c3ed441682..f7395ba709218 100644
--- a/extensions/pom.xml
+++ b/extensions/pom.xml
@@ -51,6 +51,9 @@
resteasy-mutiny
resteasy-qute
rest-client
+ rest-client-jackson
+ rest-client-jsonb
+ rest-client-jaxb
smallrye-openapi-common
smallrye-openapi
swagger-ui
diff --git a/extensions/rest-client-jackson/deployment/pom.xml b/extensions/rest-client-jackson/deployment/pom.xml
new file mode 100644
index 0000000000000..d0ba161b61338
--- /dev/null
+++ b/extensions/rest-client-jackson/deployment/pom.xml
@@ -0,0 +1,64 @@
+
+
+
+ quarkus-rest-client-jackson-parent
+ io.quarkus
+ 999-SNAPSHOT
+ ../
+
+ 4.0.0
+
+ quarkus-rest-client-jackson-deployment
+ Quarkus - REST Client - Jackson - Deployment
+
+
+
+ io.quarkus
+ quarkus-rest-client-deployment
+
+
+ io.quarkus
+ quarkus-jackson-deployment
+
+
+ io.quarkus
+ quarkus-rest-client-jackson
+
+
+
+ io.quarkus
+ quarkus-resteasy-deployment
+ test
+
+
+ io.quarkus
+ quarkus-junit5-internal
+ test
+
+
+ io.rest-assured
+ rest-assured
+ test
+
+
+
+
+
+
+ maven-compiler-plugin
+
+
+
+ io.quarkus
+ quarkus-extension-processor
+ ${project.version}
+
+
+
+
+
+
+
+
diff --git a/extensions/rest-client-jackson/deployment/src/main/java/io/quarkus/restclient/jackson/deployment/RestClientJacksonProcessor.java b/extensions/rest-client-jackson/deployment/src/main/java/io/quarkus/restclient/jackson/deployment/RestClientJacksonProcessor.java
new file mode 100644
index 0000000000000..c2427ea1cda84
--- /dev/null
+++ b/extensions/rest-client-jackson/deployment/src/main/java/io/quarkus/restclient/jackson/deployment/RestClientJacksonProcessor.java
@@ -0,0 +1,18 @@
+package io.quarkus.restclient.jackson.deployment;
+
+import io.quarkus.deployment.Capabilities;
+import io.quarkus.deployment.annotations.BuildProducer;
+import io.quarkus.deployment.annotations.BuildStep;
+import io.quarkus.deployment.builditem.CapabilityBuildItem;
+import io.quarkus.deployment.builditem.FeatureBuildItem;
+
+public class RestClientJacksonProcessor {
+
+ @BuildStep
+ void build(BuildProducer feature,
+ BuildProducer capability) {
+ feature.produce(new FeatureBuildItem(FeatureBuildItem.REST_CLIENT_JACKSON));
+
+ capability.produce(new CapabilityBuildItem(Capabilities.REST_JACKSON));
+ }
+}
diff --git a/extensions/rest-client-jackson/deployment/src/test/java/io/quarkus/restclient/jackson/deployment/ClientResource.java b/extensions/rest-client-jackson/deployment/src/test/java/io/quarkus/restclient/jackson/deployment/ClientResource.java
new file mode 100644
index 0000000000000..f107c8d39c2ce
--- /dev/null
+++ b/extensions/rest-client-jackson/deployment/src/test/java/io/quarkus/restclient/jackson/deployment/ClientResource.java
@@ -0,0 +1,33 @@
+package io.quarkus.restclient.jackson.deployment;
+
+import java.time.Month;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+
+import javax.inject.Inject;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+
+import org.eclipse.microprofile.rest.client.inject.RestClient;
+
+@Path("/client")
+public class ClientResource {
+
+ @Inject
+ @RestClient
+ RestInterface restInterface;
+
+ @GET
+ @Path("/hello")
+ public String hello() {
+ DateDto dateDto = restInterface.get();
+ ZonedDateTime zonedDateTime = dateDto.getDate();
+
+ if (zonedDateTime.getMonth().equals(Month.NOVEMBER)
+ && zonedDateTime.getZone().equals(ZoneId.of("Europe/London"))) {
+ return "OK";
+ }
+
+ return "INVALID";
+ }
+}
diff --git a/extensions/rest-client-jackson/deployment/src/test/java/io/quarkus/restclient/jackson/deployment/DateDto.java b/extensions/rest-client-jackson/deployment/src/test/java/io/quarkus/restclient/jackson/deployment/DateDto.java
new file mode 100644
index 0000000000000..a94d70bb2789e
--- /dev/null
+++ b/extensions/rest-client-jackson/deployment/src/test/java/io/quarkus/restclient/jackson/deployment/DateDto.java
@@ -0,0 +1,23 @@
+package io.quarkus.restclient.jackson.deployment;
+
+import java.time.ZonedDateTime;
+
+public class DateDto {
+
+ private ZonedDateTime date;
+
+ public DateDto() {
+ }
+
+ public DateDto(ZonedDateTime date) {
+ this.date = date;
+ }
+
+ public void setDate(ZonedDateTime date) {
+ this.date = date;
+ }
+
+ public ZonedDateTime getDate() {
+ return date;
+ }
+}
diff --git a/extensions/rest-client-jackson/deployment/src/test/java/io/quarkus/restclient/jackson/deployment/HelloResource.java b/extensions/rest-client-jackson/deployment/src/test/java/io/quarkus/restclient/jackson/deployment/HelloResource.java
new file mode 100644
index 0000000000000..89bce568ad2d0
--- /dev/null
+++ b/extensions/rest-client-jackson/deployment/src/test/java/io/quarkus/restclient/jackson/deployment/HelloResource.java
@@ -0,0 +1,27 @@
+package io.quarkus.restclient.jackson.deployment;
+
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+
+import javax.inject.Inject;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+@Produces(MediaType.APPLICATION_JSON)
+@Path("/hello")
+public class HelloResource {
+
+ @Inject
+ ObjectMapper objectMapper;
+
+ @GET
+ public String hello() throws JsonProcessingException {
+ return objectMapper
+ .writeValueAsString(new DateDto(ZonedDateTime.of(1988, 11, 17, 0, 0, 0, 0, ZoneId.of("Europe/Paris"))));
+ }
+}
diff --git a/extensions/rest-client-jackson/deployment/src/test/java/io/quarkus/restclient/jackson/deployment/JacksonRestClientTest.java b/extensions/rest-client-jackson/deployment/src/test/java/io/quarkus/restclient/jackson/deployment/JacksonRestClientTest.java
new file mode 100644
index 0000000000000..2592ce4a05d6f
--- /dev/null
+++ b/extensions/rest-client-jackson/deployment/src/test/java/io/quarkus/restclient/jackson/deployment/JacksonRestClientTest.java
@@ -0,0 +1,28 @@
+package io.quarkus.restclient.jackson.deployment;
+
+import static org.hamcrest.Matchers.is;
+
+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.test.QuarkusUnitTest;
+import io.restassured.RestAssured;
+
+public class JacksonRestClientTest {
+
+ @RegisterExtension
+ static final QuarkusUnitTest config = new QuarkusUnitTest()
+ .withConfigurationResource("application.properties")
+ .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class)
+ .addClasses(ZonedDateTimeObjectMapperCustomizer.class, DateDto.class, HelloResource.class,
+ RestInterface.class,
+ ClientResource.class));
+
+ @Test
+ public void testCustomDeserialization() {
+ RestAssured.get("/client/hello").then()
+ .body(is("OK"));
+ }
+}
diff --git a/extensions/rest-client-jackson/deployment/src/test/java/io/quarkus/restclient/jackson/deployment/RestInterface.java b/extensions/rest-client-jackson/deployment/src/test/java/io/quarkus/restclient/jackson/deployment/RestInterface.java
new file mode 100644
index 0000000000000..637a7b3424790
--- /dev/null
+++ b/extensions/rest-client-jackson/deployment/src/test/java/io/quarkus/restclient/jackson/deployment/RestInterface.java
@@ -0,0 +1,19 @@
+package io.quarkus.restclient.jackson.deployment;
+
+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.rest.client.annotation.RegisterClientHeaders;
+import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
+
+@RegisterRestClient
+@Path("/hello")
+@RegisterClientHeaders
+public interface RestInterface {
+
+ @GET
+ @Produces(MediaType.APPLICATION_JSON)
+ DateDto get();
+}
diff --git a/extensions/rest-client-jackson/deployment/src/test/java/io/quarkus/restclient/jackson/deployment/ZonedDateTimeObjectMapperCustomizer.java b/extensions/rest-client-jackson/deployment/src/test/java/io/quarkus/restclient/jackson/deployment/ZonedDateTimeObjectMapperCustomizer.java
new file mode 100644
index 0000000000000..8c0ba48a63e7f
--- /dev/null
+++ b/extensions/rest-client-jackson/deployment/src/test/java/io/quarkus/restclient/jackson/deployment/ZonedDateTimeObjectMapperCustomizer.java
@@ -0,0 +1,43 @@
+package io.quarkus.restclient.jackson.deployment;
+
+import java.io.IOException;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatterBuilder;
+
+import javax.inject.Singleton;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
+import com.fasterxml.jackson.datatype.jsr310.ser.ZonedDateTimeSerializer;
+
+import io.quarkus.jackson.ObjectMapperCustomizer;
+
+@Singleton
+public class ZonedDateTimeObjectMapperCustomizer implements ObjectMapperCustomizer {
+
+ @Override
+ public void customize(ObjectMapper objectMapper) {
+ JavaTimeModule customDateModule = new JavaTimeModule();
+ customDateModule.addSerializer(ZonedDateTime.class, new ZonedDateTimeSerializer(
+ new DateTimeFormatterBuilder().appendInstant(0).toFormatter().withZone(ZoneId.of("Z"))));
+ customDateModule.addDeserializer(ZonedDateTime.class, new ZonedDateTimeEuropeLondonDeserializer());
+ objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
+ .registerModule(customDateModule);
+ }
+
+ public static class ZonedDateTimeEuropeLondonDeserializer extends JsonDeserializer {
+
+ @Override
+ public ZonedDateTime deserialize(JsonParser p, DeserializationContext ctxt)
+ throws IOException, JsonProcessingException {
+ return ZonedDateTime.parse(p.getValueAsString())
+ .withZoneSameInstant(ZoneId.of("Europe/London"));
+ }
+ }
+}
diff --git a/extensions/rest-client-jackson/deployment/src/test/resources/application.properties b/extensions/rest-client-jackson/deployment/src/test/resources/application.properties
new file mode 100644
index 0000000000000..1d51622ea9c75
--- /dev/null
+++ b/extensions/rest-client-jackson/deployment/src/test/resources/application.properties
@@ -0,0 +1 @@
+io.quarkus.restclient.jackson.deployment.RestInterface/mp-rest/url=${test.url}
\ No newline at end of file
diff --git a/extensions/rest-client-jackson/pom.xml b/extensions/rest-client-jackson/pom.xml
new file mode 100644
index 0000000000000..aa8a722224a18
--- /dev/null
+++ b/extensions/rest-client-jackson/pom.xml
@@ -0,0 +1,20 @@
+
+
+
+ quarkus-build-parent
+ io.quarkus
+ 999-SNAPSHOT
+ ../../build-parent/pom.xml
+
+ 4.0.0
+
+ quarkus-rest-client-jackson-parent
+ Quarkus - REST Client - Jackson
+ pom
+
+ deployment
+ runtime
+
+
diff --git a/extensions/rest-client-jackson/runtime/pom.xml b/extensions/rest-client-jackson/runtime/pom.xml
new file mode 100644
index 0000000000000..6345ed9f89ed9
--- /dev/null
+++ b/extensions/rest-client-jackson/runtime/pom.xml
@@ -0,0 +1,65 @@
+
+
+
+ quarkus-rest-client-jackson-parent
+ io.quarkus
+ 999-SNAPSHOT
+ ../
+
+ 4.0.0
+
+ quarkus-rest-client-jackson
+ Quarkus - REST Client - Jackson - Runtime
+ Enable Jackson serialization for the REST Client
+
+
+ io.quarkus
+ quarkus-rest-client
+
+
+ io.quarkus
+ quarkus-jackson
+
+
+ org.jboss.resteasy
+ resteasy-jackson2-provider
+
+
+ jakarta.xml.bind
+ jakarta.xml.bind-api
+
+
+ org.checkerframework
+ checker-qual
+
+
+
+
+ org.jboss.spec.javax.xml.bind
+ jboss-jaxb-api_2.3_spec
+
+
+
+
+
+
+ io.quarkus
+ quarkus-bootstrap-maven-plugin
+
+
+ maven-compiler-plugin
+
+
+
+ io.quarkus
+ quarkus-extension-processor
+ ${project.version}
+
+
+
+
+
+
+
diff --git a/extensions/rest-client-jackson/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/rest-client-jackson/runtime/src/main/resources/META-INF/quarkus-extension.yaml
new file mode 100644
index 0000000000000..4d66fad1169b8
--- /dev/null
+++ b/extensions/rest-client-jackson/runtime/src/main/resources/META-INF/quarkus-extension.yaml
@@ -0,0 +1,14 @@
+---
+name: "REST Client Jackson"
+metadata:
+ keywords:
+ - "rest-client-jackson"
+ - "rest-client"
+ - "web-client"
+ - "microprofile-rest-client"
+ - "json"
+ - "jackson"
+ categories:
+ - "web"
+ - "serialization"
+ status: "stable"
diff --git a/extensions/rest-client-jaxb/deployment/pom.xml b/extensions/rest-client-jaxb/deployment/pom.xml
new file mode 100644
index 0000000000000..bb138d8671489
--- /dev/null
+++ b/extensions/rest-client-jaxb/deployment/pom.xml
@@ -0,0 +1,64 @@
+
+
+
+ quarkus-rest-client-jaxb-parent
+ io.quarkus
+ 999-SNAPSHOT
+ ../
+
+ 4.0.0
+
+ quarkus-rest-client-jaxb-deployment
+ Quarkus - REST Client - JAXB - Deployment
+
+
+
+ io.quarkus
+ quarkus-rest-client-deployment
+
+
+ io.quarkus
+ quarkus-rest-client-jaxb
+
+
+ io.quarkus
+ quarkus-jaxb-deployment
+
+
+
+ io.quarkus
+ quarkus-resteasy-deployment
+ test
+
+
+ io.quarkus
+ quarkus-junit5-internal
+ test
+
+
+ io.rest-assured
+ rest-assured
+ test
+
+
+
+
+
+
+ maven-compiler-plugin
+
+
+
+ io.quarkus
+ quarkus-extension-processor
+ ${project.version}
+
+
+
+
+
+
+
+
diff --git a/extensions/rest-client-jaxb/deployment/src/main/java/io/quarkus/restclient/jaxb/deployment/RestClientJaxbProcessor.java b/extensions/rest-client-jaxb/deployment/src/main/java/io/quarkus/restclient/jaxb/deployment/RestClientJaxbProcessor.java
new file mode 100755
index 0000000000000..929ff4fdfd885
--- /dev/null
+++ b/extensions/rest-client-jaxb/deployment/src/main/java/io/quarkus/restclient/jaxb/deployment/RestClientJaxbProcessor.java
@@ -0,0 +1,13 @@
+package io.quarkus.restclient.jaxb.deployment;
+
+import io.quarkus.deployment.annotations.BuildProducer;
+import io.quarkus.deployment.annotations.BuildStep;
+import io.quarkus.deployment.builditem.FeatureBuildItem;
+
+public class RestClientJaxbProcessor {
+
+ @BuildStep
+ void build(BuildProducer feature) {
+ feature.produce(new FeatureBuildItem(FeatureBuildItem.REST_CLIENT_JAXB));
+ }
+}
diff --git a/extensions/rest-client-jaxb/deployment/src/test/java/io/quarkus/restclient/jaxb/deployment/Book.java b/extensions/rest-client-jaxb/deployment/src/test/java/io/quarkus/restclient/jaxb/deployment/Book.java
new file mode 100644
index 0000000000000..ac32ad10ed93c
--- /dev/null
+++ b/extensions/rest-client-jaxb/deployment/src/test/java/io/quarkus/restclient/jaxb/deployment/Book.java
@@ -0,0 +1,24 @@
+package io.quarkus.restclient.jaxb.deployment;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+public class Book {
+
+ private String title;
+
+ public Book() {
+ }
+
+ public Book(String title) {
+ this.title = title;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+}
diff --git a/extensions/rest-client-jaxb/deployment/src/test/java/io/quarkus/restclient/jaxb/deployment/ClientResource.java b/extensions/rest-client-jaxb/deployment/src/test/java/io/quarkus/restclient/jaxb/deployment/ClientResource.java
new file mode 100644
index 0000000000000..02f20ddb1df7f
--- /dev/null
+++ b/extensions/rest-client-jaxb/deployment/src/test/java/io/quarkus/restclient/jaxb/deployment/ClientResource.java
@@ -0,0 +1,27 @@
+package io.quarkus.restclient.jaxb.deployment;
+
+import javax.inject.Inject;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+
+import org.eclipse.microprofile.rest.client.inject.RestClient;
+
+@Path("/client")
+public class ClientResource {
+
+ @Inject
+ @RestClient
+ RestInterface restInterface;
+
+ @GET
+ @Path("/hello")
+ public String hello() {
+ Book book = restInterface.get();
+
+ if ("L'axe du loup".equals(book.getTitle())) {
+ return "OK";
+ }
+
+ return "INVALID";
+ }
+}
diff --git a/extensions/rest-client-jaxb/deployment/src/test/java/io/quarkus/restclient/jaxb/deployment/HelloResource.java b/extensions/rest-client-jaxb/deployment/src/test/java/io/quarkus/restclient/jaxb/deployment/HelloResource.java
new file mode 100644
index 0000000000000..cd54bc7b65a66
--- /dev/null
+++ b/extensions/rest-client-jaxb/deployment/src/test/java/io/quarkus/restclient/jaxb/deployment/HelloResource.java
@@ -0,0 +1,16 @@
+package io.quarkus.restclient.jaxb.deployment;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+
+@Produces(MediaType.APPLICATION_XML)
+@Path("/hello")
+public class HelloResource {
+
+ @GET
+ public String hello() {
+ return "L'axe du loup";
+ }
+}
diff --git a/extensions/rest-client-jaxb/deployment/src/test/java/io/quarkus/restclient/jaxb/deployment/JaxbRestClientTest.java b/extensions/rest-client-jaxb/deployment/src/test/java/io/quarkus/restclient/jaxb/deployment/JaxbRestClientTest.java
new file mode 100644
index 0000000000000..f665f95352afb
--- /dev/null
+++ b/extensions/rest-client-jaxb/deployment/src/test/java/io/quarkus/restclient/jaxb/deployment/JaxbRestClientTest.java
@@ -0,0 +1,29 @@
+package io.quarkus.restclient.jaxb.deployment;
+
+import static org.hamcrest.Matchers.is;
+
+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.test.QuarkusUnitTest;
+import io.restassured.RestAssured;
+
+public class JaxbRestClientTest {
+
+ @RegisterExtension
+ static final QuarkusUnitTest config = new QuarkusUnitTest()
+ .withConfigurationResource("application.properties")
+ .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class)
+ .addClasses(Book.class,
+ HelloResource.class,
+ RestInterface.class,
+ ClientResource.class));
+
+ @Test
+ public void testJaxb() {
+ RestAssured.get("/client/hello").then()
+ .body(is("OK"));
+ }
+}
diff --git a/extensions/rest-client-jaxb/deployment/src/test/java/io/quarkus/restclient/jaxb/deployment/RestInterface.java b/extensions/rest-client-jaxb/deployment/src/test/java/io/quarkus/restclient/jaxb/deployment/RestInterface.java
new file mode 100644
index 0000000000000..f985b39eebe5e
--- /dev/null
+++ b/extensions/rest-client-jaxb/deployment/src/test/java/io/quarkus/restclient/jaxb/deployment/RestInterface.java
@@ -0,0 +1,19 @@
+package io.quarkus.restclient.jaxb.deployment;
+
+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.rest.client.annotation.RegisterClientHeaders;
+import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
+
+@RegisterRestClient
+@Path("/hello")
+@RegisterClientHeaders
+public interface RestInterface {
+
+ @GET
+ @Produces(MediaType.APPLICATION_XML)
+ Book get();
+}
diff --git a/extensions/rest-client-jaxb/deployment/src/test/resources/application.properties b/extensions/rest-client-jaxb/deployment/src/test/resources/application.properties
new file mode 100644
index 0000000000000..99628eb948087
--- /dev/null
+++ b/extensions/rest-client-jaxb/deployment/src/test/resources/application.properties
@@ -0,0 +1 @@
+io.quarkus.restclient.jaxb.deployment.RestInterface/mp-rest/url=${test.url}
\ No newline at end of file
diff --git a/extensions/rest-client-jaxb/pom.xml b/extensions/rest-client-jaxb/pom.xml
new file mode 100644
index 0000000000000..9f3f7210e808f
--- /dev/null
+++ b/extensions/rest-client-jaxb/pom.xml
@@ -0,0 +1,20 @@
+
+
+
+ quarkus-build-parent
+ io.quarkus
+ 999-SNAPSHOT
+ ../../build-parent/pom.xml
+
+ 4.0.0
+
+ quarkus-rest-client-jaxb-parent
+ Quarkus - REST Client - JAXB
+ pom
+
+ deployment
+ runtime
+
+
diff --git a/extensions/rest-client-jaxb/runtime/pom.xml b/extensions/rest-client-jaxb/runtime/pom.xml
new file mode 100644
index 0000000000000..77345e8877a65
--- /dev/null
+++ b/extensions/rest-client-jaxb/runtime/pom.xml
@@ -0,0 +1,55 @@
+
+
+
+ quarkus-rest-client-jaxb-parent
+ io.quarkus
+ 999-SNAPSHOT
+ ../
+
+ 4.0.0
+
+ quarkus-rest-client-jaxb
+ Quarkus - REST Client - JAXB - Runtime
+ Enable XML serialization for the REST Client
+
+
+ io.quarkus
+ quarkus-rest-client
+
+
+ io.quarkus
+ quarkus-jaxb
+
+
+ org.jboss.resteasy
+ resteasy-jaxb-provider
+
+
+ org.jboss.spec.javax.xml.bind
+ jboss-jaxb-api_2.3_spec
+
+
+
+
+
+
+ io.quarkus
+ quarkus-bootstrap-maven-plugin
+
+
+ maven-compiler-plugin
+
+
+
+ io.quarkus
+ quarkus-extension-processor
+ ${project.version}
+
+
+
+
+
+
+
diff --git a/extensions/rest-client-jaxb/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/rest-client-jaxb/runtime/src/main/resources/META-INF/quarkus-extension.yaml
new file mode 100644
index 0000000000000..25c6fd88fe662
--- /dev/null
+++ b/extensions/rest-client-jaxb/runtime/src/main/resources/META-INF/quarkus-extension.yaml
@@ -0,0 +1,13 @@
+---
+name: "REST Client JAXB"
+metadata:
+ keywords:
+ - "rest-client-jaxb"
+ - "rest-client"
+ - "web-client"
+ - "microprofile-rest-client"
+ - "jaxb"
+ categories:
+ - "web"
+ - "serialization"
+ status: "stable"
diff --git a/extensions/rest-client-jsonb/deployment/pom.xml b/extensions/rest-client-jsonb/deployment/pom.xml
new file mode 100644
index 0000000000000..0505299df2dba
--- /dev/null
+++ b/extensions/rest-client-jsonb/deployment/pom.xml
@@ -0,0 +1,64 @@
+
+
+
+ quarkus-rest-client-jsonb-parent
+ io.quarkus
+ 999-SNAPSHOT
+ ../
+
+ 4.0.0
+
+ quarkus-rest-client-jsonb-deployment
+ Quarkus - REST Client - JSON-B - Deployment
+
+
+
+ io.quarkus
+ quarkus-rest-client-deployment
+
+
+ io.quarkus
+ quarkus-rest-client-jsonb
+
+
+ io.quarkus
+ quarkus-jsonb-deployment
+
+
+
+ io.quarkus
+ quarkus-resteasy-deployment
+ test
+
+
+ io.quarkus
+ quarkus-junit5-internal
+ test
+
+
+ io.rest-assured
+ rest-assured
+ test
+
+
+
+
+
+
+ maven-compiler-plugin
+
+
+
+ io.quarkus
+ quarkus-extension-processor
+ ${project.version}
+
+
+
+
+
+
+
+
diff --git a/extensions/rest-client-jsonb/deployment/src/main/java/io/quarkus/restclient/jsonb/deployment/RestClientJsonbProcessor.java b/extensions/rest-client-jsonb/deployment/src/main/java/io/quarkus/restclient/jsonb/deployment/RestClientJsonbProcessor.java
new file mode 100755
index 0000000000000..150147e8883e3
--- /dev/null
+++ b/extensions/rest-client-jsonb/deployment/src/main/java/io/quarkus/restclient/jsonb/deployment/RestClientJsonbProcessor.java
@@ -0,0 +1,18 @@
+package io.quarkus.restclient.jsonb.deployment;
+
+import io.quarkus.deployment.Capabilities;
+import io.quarkus.deployment.annotations.BuildProducer;
+import io.quarkus.deployment.annotations.BuildStep;
+import io.quarkus.deployment.builditem.CapabilityBuildItem;
+import io.quarkus.deployment.builditem.FeatureBuildItem;
+
+public class RestClientJsonbProcessor {
+
+ @BuildStep
+ void build(BuildProducer feature,
+ BuildProducer capability) {
+ feature.produce(new FeatureBuildItem(FeatureBuildItem.REST_CLIENT_JSONB));
+
+ capability.produce(new CapabilityBuildItem(Capabilities.REST_JSONB));
+ }
+}
diff --git a/extensions/rest-client-jsonb/deployment/src/test/java/io/quarkus/restclient/jsonb/deployment/ClientResource.java b/extensions/rest-client-jsonb/deployment/src/test/java/io/quarkus/restclient/jsonb/deployment/ClientResource.java
new file mode 100644
index 0000000000000..1158b89e0c5f6
--- /dev/null
+++ b/extensions/rest-client-jsonb/deployment/src/test/java/io/quarkus/restclient/jsonb/deployment/ClientResource.java
@@ -0,0 +1,33 @@
+package io.quarkus.restclient.jsonb.deployment;
+
+import java.time.Month;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+
+import javax.inject.Inject;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+
+import org.eclipse.microprofile.rest.client.inject.RestClient;
+
+@Path("/client")
+public class ClientResource {
+
+ @Inject
+ @RestClient
+ RestInterface restInterface;
+
+ @GET
+ @Path("/hello")
+ public String hello() {
+ DateDto dateDto = restInterface.get();
+ ZonedDateTime zonedDateTime = dateDto.getDate();
+
+ if (zonedDateTime.getMonth().equals(Month.NOVEMBER)
+ && zonedDateTime.getZone().equals(ZoneId.of("Europe/Paris"))) {
+ return "OK";
+ }
+
+ return "INVALID";
+ }
+}
diff --git a/extensions/rest-client-jsonb/deployment/src/test/java/io/quarkus/restclient/jsonb/deployment/DateDto.java b/extensions/rest-client-jsonb/deployment/src/test/java/io/quarkus/restclient/jsonb/deployment/DateDto.java
new file mode 100644
index 0000000000000..52d8c639ced52
--- /dev/null
+++ b/extensions/rest-client-jsonb/deployment/src/test/java/io/quarkus/restclient/jsonb/deployment/DateDto.java
@@ -0,0 +1,23 @@
+package io.quarkus.restclient.jsonb.deployment;
+
+import java.time.ZonedDateTime;
+
+public class DateDto {
+
+ private ZonedDateTime date;
+
+ public DateDto() {
+ }
+
+ public DateDto(ZonedDateTime date) {
+ this.date = date;
+ }
+
+ public void setDate(ZonedDateTime date) {
+ this.date = date;
+ }
+
+ public ZonedDateTime getDate() {
+ return date;
+ }
+}
diff --git a/extensions/rest-client-jsonb/deployment/src/test/java/io/quarkus/restclient/jsonb/deployment/HelloResource.java b/extensions/rest-client-jsonb/deployment/src/test/java/io/quarkus/restclient/jsonb/deployment/HelloResource.java
new file mode 100644
index 0000000000000..6149f3a87a0c8
--- /dev/null
+++ b/extensions/rest-client-jsonb/deployment/src/test/java/io/quarkus/restclient/jsonb/deployment/HelloResource.java
@@ -0,0 +1,24 @@
+package io.quarkus.restclient.jsonb.deployment;
+
+import java.time.ZonedDateTime;
+
+import javax.inject.Inject;
+import javax.json.bind.Jsonb;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+
+@Produces(MediaType.APPLICATION_JSON)
+@Path("/hello")
+public class HelloResource {
+
+ @Inject
+ Jsonb jsonb;
+
+ @GET
+ public String hello() {
+ // we don't care about the value here as we will use a custom deserializer that returns a fixed value
+ return jsonb.toJson(new DateDto(ZonedDateTime.now()));
+ }
+}
diff --git a/extensions/rest-client-jsonb/deployment/src/test/java/io/quarkus/restclient/jsonb/deployment/JsonbRestClientTest.java b/extensions/rest-client-jsonb/deployment/src/test/java/io/quarkus/restclient/jsonb/deployment/JsonbRestClientTest.java
new file mode 100644
index 0000000000000..2317d1bcd331f
--- /dev/null
+++ b/extensions/rest-client-jsonb/deployment/src/test/java/io/quarkus/restclient/jsonb/deployment/JsonbRestClientTest.java
@@ -0,0 +1,28 @@
+package io.quarkus.restclient.jsonb.deployment;
+
+import static org.hamcrest.Matchers.is;
+
+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.test.QuarkusUnitTest;
+import io.restassured.RestAssured;
+
+public class JsonbRestClientTest {
+
+ @RegisterExtension
+ static final QuarkusUnitTest config = new QuarkusUnitTest()
+ .withConfigurationResource("application.properties")
+ .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class)
+ .addClasses(ZonedDateTimeJsonbConfigCustomizer.class, DateDto.class, HelloResource.class,
+ RestInterface.class,
+ ClientResource.class));
+
+ @Test
+ public void testCustomDeserialization() {
+ RestAssured.get("/client/hello").then()
+ .body(is("OK"));
+ }
+}
diff --git a/extensions/rest-client-jsonb/deployment/src/test/java/io/quarkus/restclient/jsonb/deployment/RestInterface.java b/extensions/rest-client-jsonb/deployment/src/test/java/io/quarkus/restclient/jsonb/deployment/RestInterface.java
new file mode 100644
index 0000000000000..6588dc1ab3f2d
--- /dev/null
+++ b/extensions/rest-client-jsonb/deployment/src/test/java/io/quarkus/restclient/jsonb/deployment/RestInterface.java
@@ -0,0 +1,19 @@
+package io.quarkus.restclient.jsonb.deployment;
+
+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.rest.client.annotation.RegisterClientHeaders;
+import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
+
+@RegisterRestClient
+@Path("/hello")
+@RegisterClientHeaders
+public interface RestInterface {
+
+ @GET
+ @Produces(MediaType.APPLICATION_JSON)
+ DateDto get();
+}
diff --git a/extensions/rest-client-jsonb/deployment/src/test/java/io/quarkus/restclient/jsonb/deployment/ZonedDateTimeJsonbConfigCustomizer.java b/extensions/rest-client-jsonb/deployment/src/test/java/io/quarkus/restclient/jsonb/deployment/ZonedDateTimeJsonbConfigCustomizer.java
new file mode 100644
index 0000000000000..12bcd9c99ec52
--- /dev/null
+++ b/extensions/rest-client-jsonb/deployment/src/test/java/io/quarkus/restclient/jsonb/deployment/ZonedDateTimeJsonbConfigCustomizer.java
@@ -0,0 +1,30 @@
+package io.quarkus.restclient.jsonb.deployment;
+
+import java.lang.reflect.Type;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+
+import javax.inject.Singleton;
+import javax.json.bind.JsonbConfig;
+import javax.json.bind.serializer.DeserializationContext;
+import javax.json.bind.serializer.JsonbDeserializer;
+import javax.json.stream.JsonParser;
+
+import io.quarkus.jsonb.JsonbConfigCustomizer;
+
+@Singleton
+public class ZonedDateTimeJsonbConfigCustomizer implements JsonbConfigCustomizer {
+
+ @Override
+ public void customize(JsonbConfig jsonbConfig) {
+ jsonbConfig.withDeserializers(new ZonedDateTimeWeirdDeserializer());
+ }
+
+ public static class ZonedDateTimeWeirdDeserializer implements JsonbDeserializer {
+
+ @Override
+ public ZonedDateTime deserialize(JsonParser parser, DeserializationContext ctx, Type rtType) {
+ return ZonedDateTime.of(1988, 11, 17, 0, 0, 0, 0, ZoneId.of("Europe/Paris"));
+ }
+ }
+}
diff --git a/extensions/rest-client-jsonb/deployment/src/test/resources/application.properties b/extensions/rest-client-jsonb/deployment/src/test/resources/application.properties
new file mode 100644
index 0000000000000..4bff6c7629f29
--- /dev/null
+++ b/extensions/rest-client-jsonb/deployment/src/test/resources/application.properties
@@ -0,0 +1 @@
+io.quarkus.restclient.jsonb.deployment.RestInterface/mp-rest/url=${test.url}
\ No newline at end of file
diff --git a/extensions/rest-client-jsonb/pom.xml b/extensions/rest-client-jsonb/pom.xml
new file mode 100644
index 0000000000000..db67cf68d776b
--- /dev/null
+++ b/extensions/rest-client-jsonb/pom.xml
@@ -0,0 +1,20 @@
+
+
+
+ quarkus-build-parent
+ io.quarkus
+ 999-SNAPSHOT
+ ../../build-parent/pom.xml
+
+ 4.0.0
+
+ quarkus-rest-client-jsonb-parent
+ Quarkus - REST Client - JSON-B
+ pom
+
+ deployment
+ runtime
+
+
diff --git a/extensions/rest-client-jsonb/runtime/pom.xml b/extensions/rest-client-jsonb/runtime/pom.xml
new file mode 100644
index 0000000000000..f25528fdba94f
--- /dev/null
+++ b/extensions/rest-client-jsonb/runtime/pom.xml
@@ -0,0 +1,60 @@
+
+
+
+ quarkus-rest-client-jsonb-parent
+ io.quarkus
+ 999-SNAPSHOT
+ ../
+
+ 4.0.0
+
+ quarkus-rest-client-jsonb
+ Quarkus - REST Client - JSON-B - Runtime
+ Enable JSON-B serialization for the REST client
+
+
+
+ io.quarkus
+ quarkus-rest-client
+
+
+ io.quarkus
+ quarkus-jsonb
+
+
+ org.jboss.resteasy
+ resteasy-json-binding-provider
+
+
+ org.jboss.resteasy
+ resteasy-json-p-provider
+
+
+ commons-io
+ commons-io
+
+
+
+
+
+
+ io.quarkus
+ quarkus-bootstrap-maven-plugin
+
+
+ maven-compiler-plugin
+
+
+
+ io.quarkus
+ quarkus-extension-processor
+ ${project.version}
+
+
+
+
+
+
+
diff --git a/extensions/rest-client-jsonb/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/rest-client-jsonb/runtime/src/main/resources/META-INF/quarkus-extension.yaml
new file mode 100644
index 0000000000000..b319d5b3bbaac
--- /dev/null
+++ b/extensions/rest-client-jsonb/runtime/src/main/resources/META-INF/quarkus-extension.yaml
@@ -0,0 +1,14 @@
+---
+name: "REST Client JSON-B"
+metadata:
+ keywords:
+ - "rest-client-jsonb"
+ - "rest-client"
+ - "web-client"
+ - "microprofile-rest-client"
+ - "json"
+ - "jsonb"
+ categories:
+ - "web"
+ - "serialization"
+ status: "stable"
diff --git a/extensions/rest-client/deployment/pom.xml b/extensions/rest-client/deployment/pom.xml
index 899a0a6b61835..87422b675ea5e 100644
--- a/extensions/rest-client/deployment/pom.xml
+++ b/extensions/rest-client/deployment/pom.xml
@@ -11,7 +11,7 @@
4.0.0
quarkus-rest-client-deployment
- Quarkus - REST client - Deployment
+ Quarkus - REST Client - Deployment
diff --git a/extensions/rest-client/pom.xml b/extensions/rest-client/pom.xml
index 05ff19bb5bf35..6753563041001 100644
--- a/extensions/rest-client/pom.xml
+++ b/extensions/rest-client/pom.xml
@@ -11,7 +11,7 @@
4.0.0
quarkus-rest-client-parent
- Quarkus - REST client
+ Quarkus - REST Client
pom
deployment
diff --git a/extensions/rest-client/runtime/pom.xml b/extensions/rest-client/runtime/pom.xml
index 123991ff71fa9..0eb84cb596d9a 100644
--- a/extensions/rest-client/runtime/pom.xml
+++ b/extensions/rest-client/runtime/pom.xml
@@ -11,7 +11,7 @@
4.0.0
quarkus-rest-client
- Quarkus - REST client - Runtime
+ Quarkus - REST Client - Runtime
Call REST services
diff --git a/extensions/resteasy-common/deployment/src/main/java/io/quarkus/resteasy/common/deployment/ResteasyCommonProcessor.java b/extensions/resteasy-common/deployment/src/main/java/io/quarkus/resteasy/common/deployment/ResteasyCommonProcessor.java
index 4e826751ac24f..7b91c994c2699 100644
--- a/extensions/resteasy-common/deployment/src/main/java/io/quarkus/resteasy/common/deployment/ResteasyCommonProcessor.java
+++ b/extensions/resteasy-common/deployment/src/main/java/io/quarkus/resteasy/common/deployment/ResteasyCommonProcessor.java
@@ -38,8 +38,11 @@
import org.jboss.resteasy.plugins.providers.sse.SseConstants;
import org.jboss.resteasy.spi.InjectorFactory;
+import io.quarkus.arc.deployment.AdditionalBeanBuildItem;
import io.quarkus.arc.deployment.BeanArchiveIndexBuildItem;
import io.quarkus.arc.deployment.BeanContainerBuildItem;
+import io.quarkus.arc.deployment.UnremovableBeanBuildItem;
+import io.quarkus.arc.processor.DotNames;
import io.quarkus.deployment.Capabilities;
import io.quarkus.deployment.annotations.BuildProducer;
import io.quarkus.deployment.annotations.BuildStep;
@@ -57,6 +60,7 @@
import io.quarkus.runtime.configuration.MemorySize;
public class ResteasyCommonProcessor {
+
private static final Logger LOGGER = Logger.getLogger(ResteasyCommonProcessor.class.getName());
private static final ProviderDiscoverer[] PROVIDER_DISCOVERERS = {
@@ -69,6 +73,13 @@ public class ResteasyCommonProcessor {
new ProviderDiscoverer(ResteasyDotNames.PUT, true, false)
};
+ private static final DotName QUARKUS_OBJECT_MAPPER_CONTEXT_RESOLVER = DotName
+ .createSimple("io.quarkus.resteasy.common.runtime.jackson.QuarkusObjectMapperContextResolver");
+ private static final DotName OBJECT_MAPPER = DotName.createSimple("com.fasterxml.jackson.databind.ObjectMapper");
+ private static final DotName QUARKUS_JSONB_CONTEXT_RESOLVER = DotName
+ .createSimple("io.quarkus.resteasy.common.runtime.jsonb.QuarkusJsonbContextResolver");
+ private static final DotName JSONB = DotName.createSimple("javax.json.bind.Jsonb");
+
private ResteasyCommonConfig resteasyCommonConfig;
@ConfigRoot(name = "resteasy")
@@ -191,6 +202,62 @@ JaxrsProvidersToRegisterBuildItem setupProviders(BuildProducer jaxrsProvider,
+ BuildProducer additionalBean,
+ BuildProducer unremovable) {
+
+ if (capabilities.isCapabilityPresent(Capabilities.REST_JACKSON)) {
+ registerJsonContextResolver(OBJECT_MAPPER, QUARKUS_OBJECT_MAPPER_CONTEXT_RESOLVER, combinedIndexBuildItem,
+ jaxrsProvider, additionalBean, unremovable);
+ }
+
+ if (capabilities.isCapabilityPresent(Capabilities.REST_JSONB)) {
+ registerJsonContextResolver(JSONB, QUARKUS_JSONB_CONTEXT_RESOLVER, combinedIndexBuildItem, jaxrsProvider,
+ additionalBean, unremovable);
+ }
+ }
+
+ private void registerJsonContextResolver(
+ DotName jsonImplementation,
+ DotName jsonContextResolver,
+ CombinedIndexBuildItem combinedIndexBuildItem,
+ BuildProducer jaxrsProvider,
+ BuildProducer additionalBean,
+ BuildProducer unremovable) {
+
+ IndexView index = combinedIndexBuildItem.getIndex();
+
+ jaxrsProvider.produce(new ResteasyJaxrsProviderBuildItem(jsonContextResolver.toString()));
+
+ // this needs to be registered manually since the runtime module is not indexed by Jandex
+ additionalBean.produce(AdditionalBeanBuildItem.unremovableOf(jsonContextResolver.toString()));
+ Set userSuppliedProducers = getUserSuppliedJsonProducerBeans(index, jsonImplementation);
+ if (!userSuppliedProducers.isEmpty()) {
+ unremovable.produce(
+ new UnremovableBeanBuildItem(new UnremovableBeanBuildItem.BeanClassNamesExclusion(userSuppliedProducers)));
+ }
+ }
+
+ /*
+ * We need to find all the user supplied producers and mark them as unremovable since there are no actual injection points
+ * for ObjectMapper/Jsonb.
+ */
+ private Set getUserSuppliedJsonProducerBeans(IndexView index, DotName jsonImplementation) {
+ Set result = new HashSet<>();
+ for (AnnotationInstance annotation : index.getAnnotations(DotNames.PRODUCES)) {
+ if (annotation.target().kind() != AnnotationTarget.Kind.METHOD) {
+ continue;
+ }
+ if (jsonImplementation.equals(annotation.target().asMethod().returnType().name())) {
+ result.add(annotation.target().asMethod().declaringClass().name().toString());
+ }
+ }
+ return result;
+ }
+
private void checkProperConfigAccessInProvider(AnnotationInstance instance) {
List configPropertyInstances = instance.target().asClass().annotations()
.get(ResteasyDotNames.CONFIG_PROPERTY);
diff --git a/extensions/resteasy-common/runtime/pom.xml b/extensions/resteasy-common/runtime/pom.xml
index 35ae2dcf4108f..f867901d5f320 100644
--- a/extensions/resteasy-common/runtime/pom.xml
+++ b/extensions/resteasy-common/runtime/pom.xml
@@ -12,7 +12,7 @@
quarkus-resteasy-common
Quarkus - RESTEasy - Common - Runtime
- REST framework implementing JAX-RS and more
+ Components common to the RESTEasy server and the REST Client
org.graalvm.nativeimage
@@ -46,6 +46,16 @@
com.sun.activation
jakarta.activation
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ true
+
+
+ jakarta.json.bind
+ jakarta.json.bind-api
+ true
+
diff --git a/extensions/resteasy-jackson/runtime/src/main/java/io/quarkus/resteasy/jackson/runtime/QuarkusObjectMapperContextResolver.java b/extensions/resteasy-common/runtime/src/main/java/io/quarkus/resteasy/common/runtime/jackson/QuarkusObjectMapperContextResolver.java
similarity index 92%
rename from extensions/resteasy-jackson/runtime/src/main/java/io/quarkus/resteasy/jackson/runtime/QuarkusObjectMapperContextResolver.java
rename to extensions/resteasy-common/runtime/src/main/java/io/quarkus/resteasy/common/runtime/jackson/QuarkusObjectMapperContextResolver.java
index 45e5c983b5db4..338831749d370 100644
--- a/extensions/resteasy-jackson/runtime/src/main/java/io/quarkus/resteasy/jackson/runtime/QuarkusObjectMapperContextResolver.java
+++ b/extensions/resteasy-common/runtime/src/main/java/io/quarkus/resteasy/common/runtime/jackson/QuarkusObjectMapperContextResolver.java
@@ -1,4 +1,4 @@
-package io.quarkus.resteasy.jackson.runtime;
+package io.quarkus.resteasy.common.runtime.jackson;
import javax.annotation.Priority;
import javax.enterprise.context.ApplicationScoped;
diff --git a/extensions/resteasy-jsonb/runtime/src/main/java/io/quarkus/resteasy/jsonb/runtime/QuarkusJsonbContextResolver.java b/extensions/resteasy-common/runtime/src/main/java/io/quarkus/resteasy/common/runtime/jsonb/QuarkusJsonbContextResolver.java
similarity index 92%
rename from extensions/resteasy-jsonb/runtime/src/main/java/io/quarkus/resteasy/jsonb/runtime/QuarkusJsonbContextResolver.java
rename to extensions/resteasy-common/runtime/src/main/java/io/quarkus/resteasy/common/runtime/jsonb/QuarkusJsonbContextResolver.java
index a392b321934e0..16b9412db5853 100644
--- a/extensions/resteasy-jsonb/runtime/src/main/java/io/quarkus/resteasy/jsonb/runtime/QuarkusJsonbContextResolver.java
+++ b/extensions/resteasy-common/runtime/src/main/java/io/quarkus/resteasy/common/runtime/jsonb/QuarkusJsonbContextResolver.java
@@ -1,4 +1,4 @@
-package io.quarkus.resteasy.jsonb.runtime;
+package io.quarkus.resteasy.common.runtime.jsonb;
import javax.annotation.Priority;
import javax.enterprise.context.ApplicationScoped;
diff --git a/extensions/resteasy-jackson/deployment/src/main/java/io/quarkus/resteasy/jackson/deployment/ResteasyJacksonProcessor.java b/extensions/resteasy-jackson/deployment/src/main/java/io/quarkus/resteasy/jackson/deployment/ResteasyJacksonProcessor.java
index 0ed222343af8f..378a310b9861a 100644
--- a/extensions/resteasy-jackson/deployment/src/main/java/io/quarkus/resteasy/jackson/deployment/ResteasyJacksonProcessor.java
+++ b/extensions/resteasy-jackson/deployment/src/main/java/io/quarkus/resteasy/jackson/deployment/ResteasyJacksonProcessor.java
@@ -1,68 +1,21 @@
package io.quarkus.resteasy.jackson.deployment;
-import java.util.HashSet;
-import java.util.Set;
-
-import org.jboss.jandex.AnnotationInstance;
-import org.jboss.jandex.AnnotationTarget;
-import org.jboss.jandex.DotName;
-import org.jboss.jandex.IndexView;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-
-import io.quarkus.arc.deployment.AdditionalBeanBuildItem;
-import io.quarkus.arc.deployment.UnremovableBeanBuildItem;
-import io.quarkus.arc.processor.DotNames;
import io.quarkus.deployment.Capabilities;
import io.quarkus.deployment.annotations.BuildProducer;
import io.quarkus.deployment.annotations.BuildStep;
-import io.quarkus.deployment.builditem.CombinedIndexBuildItem;
+import io.quarkus.deployment.builditem.CapabilityBuildItem;
import io.quarkus.deployment.builditem.FeatureBuildItem;
-import io.quarkus.resteasy.common.spi.ResteasyJaxrsProviderBuildItem;
-import io.quarkus.resteasy.jackson.runtime.QuarkusObjectMapperContextResolver;
public class ResteasyJacksonProcessor {
- private static final DotName OBJECT_MAPPER = DotName.createSimple(ObjectMapper.class.getName());
-
- @BuildStep(providesCapabilities = { Capabilities.RESTEASY_JSON_EXTENSION })
- void build(BuildProducer feature) {
+ @BuildStep
+ void feature(BuildProducer feature) {
feature.produce(new FeatureBuildItem(FeatureBuildItem.RESTEASY_JACKSON));
}
@BuildStep
- void register(CombinedIndexBuildItem combinedIndexBuildItem,
- BuildProducer jaxrsProvider,
- BuildProducer additionalBean,
- BuildProducer unremovable) {
-
- IndexView index = combinedIndexBuildItem.getIndex();
-
- jaxrsProvider.produce(new ResteasyJaxrsProviderBuildItem(QuarkusObjectMapperContextResolver.class.getName()));
-
- // this needs to be registered manually since the runtime module is not indexed by Jandex
- additionalBean.produce(AdditionalBeanBuildItem.unremovableOf(QuarkusObjectMapperContextResolver.class));
- Set userSuppliedProducers = getUserSuppliedJacksonProducerBeans(index);
- if (!userSuppliedProducers.isEmpty()) {
- unremovable.produce(
- new UnremovableBeanBuildItem(new UnremovableBeanBuildItem.BeanClassNamesExclusion(userSuppliedProducers)));
- }
- }
-
- /*
- * We need to find all the user supplied producers and mark them as unremovable since there are no actual injection points
- * for the ObjectMapper
- */
- private Set getUserSuppliedJacksonProducerBeans(IndexView index) {
- Set result = new HashSet<>();
- for (AnnotationInstance annotation : index.getAnnotations(DotNames.PRODUCES)) {
- if (annotation.target().kind() != AnnotationTarget.Kind.METHOD) {
- continue;
- }
- if (OBJECT_MAPPER.equals(annotation.target().asMethod().returnType().name())) {
- result.add(annotation.target().asMethod().declaringClass().name().toString());
- }
- }
- return result;
+ void capabilities(BuildProducer capability) {
+ capability.produce(new CapabilityBuildItem(Capabilities.RESTEASY_JSON_EXTENSION));
+ capability.produce(new CapabilityBuildItem(Capabilities.REST_JACKSON));
}
}
diff --git a/extensions/resteasy-jsonb/deployment/src/main/java/io/quarkus/resteasy/jsonb/deployment/ResteasyJsonbProcessor.java b/extensions/resteasy-jsonb/deployment/src/main/java/io/quarkus/resteasy/jsonb/deployment/ResteasyJsonbProcessor.java
index 8d9467f221de7..0ac9dbbe76990 100755
--- a/extensions/resteasy-jsonb/deployment/src/main/java/io/quarkus/resteasy/jsonb/deployment/ResteasyJsonbProcessor.java
+++ b/extensions/resteasy-jsonb/deployment/src/main/java/io/quarkus/resteasy/jsonb/deployment/ResteasyJsonbProcessor.java
@@ -1,74 +1,21 @@
package io.quarkus.resteasy.jsonb.deployment;
-import java.util.HashSet;
-import java.util.Set;
-
-import javax.json.bind.Jsonb;
-
-import org.jboss.jandex.AnnotationInstance;
-import org.jboss.jandex.AnnotationTarget;
-import org.jboss.jandex.DotName;
-import org.jboss.jandex.IndexView;
-
-import io.quarkus.arc.deployment.AdditionalBeanBuildItem;
-import io.quarkus.arc.deployment.UnremovableBeanBuildItem;
-import io.quarkus.arc.processor.DotNames;
import io.quarkus.deployment.Capabilities;
import io.quarkus.deployment.annotations.BuildProducer;
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.builditem.CapabilityBuildItem;
-import io.quarkus.deployment.builditem.CombinedIndexBuildItem;
import io.quarkus.deployment.builditem.FeatureBuildItem;
-import io.quarkus.resteasy.common.spi.ResteasyJaxrsProviderBuildItem;
-import io.quarkus.resteasy.jsonb.runtime.QuarkusJsonbContextResolver;
public class ResteasyJsonbProcessor {
- private static final DotName JSONB = DotName.createSimple(Jsonb.class.getName());
-
- @BuildStep
- CapabilityBuildItem capability() {
- return new CapabilityBuildItem(Capabilities.RESTEASY_JSON_EXTENSION);
- }
-
@BuildStep
- void build(BuildProducer feature) {
+ void feature(BuildProducer feature) {
feature.produce(new FeatureBuildItem(FeatureBuildItem.RESTEASY_JSONB));
}
@BuildStep
- void register(CombinedIndexBuildItem combinedIndexBuildItem,
- BuildProducer jaxrsProvider,
- BuildProducer additionalBean,
- BuildProducer unremovable) {
-
- IndexView index = combinedIndexBuildItem.getIndex();
-
- jaxrsProvider.produce(new ResteasyJaxrsProviderBuildItem(QuarkusJsonbContextResolver.class.getName()));
-
- // this needs to be registered manually since the runtime module is not indexed by Jandex
- additionalBean.produce(AdditionalBeanBuildItem.unremovableOf(QuarkusJsonbContextResolver.class));
- Set userSuppliedProducers = getUserSuppliedJsonbProducerBeans(index);
- if (!userSuppliedProducers.isEmpty()) {
- unremovable.produce(
- new UnremovableBeanBuildItem(new UnremovableBeanBuildItem.BeanClassNamesExclusion(userSuppliedProducers)));
- }
- }
-
- /*
- * We need to find all the user supplied producers and mark them as unremovable since there might be no injection points
- * for the Jsonb
- */
- private Set getUserSuppliedJsonbProducerBeans(IndexView index) {
- Set result = new HashSet<>();
- for (AnnotationInstance annotation : index.getAnnotations(DotNames.PRODUCES)) {
- if (annotation.target().kind() != AnnotationTarget.Kind.METHOD) {
- continue;
- }
- if (JSONB.equals(annotation.target().asMethod().returnType().name())) {
- result.add(annotation.target().asMethod().declaringClass().name().toString());
- }
- }
- return result;
+ void capabilities(BuildProducer capability) {
+ capability.produce(new CapabilityBuildItem(Capabilities.RESTEASY_JSON_EXTENSION));
+ capability.produce(new CapabilityBuildItem(Capabilities.REST_JSONB));
}
}
diff --git a/integration-tests/resteasy-jackson/src/test/java/io/quarkus/it/resteasy/jackson/GeneratedClassesTest.java b/integration-tests/resteasy-jackson/src/test/java/io/quarkus/it/resteasy/jackson/GeneratedClassesTest.java
index 87ea6501174bd..f5abd253a65cf 100644
--- a/integration-tests/resteasy-jackson/src/test/java/io/quarkus/it/resteasy/jackson/GeneratedClassesTest.java
+++ b/integration-tests/resteasy-jackson/src/test/java/io/quarkus/it/resteasy/jackson/GeneratedClassesTest.java
@@ -16,9 +16,9 @@ void testGeneratedContextResolver() {
private Object generatedContextResolver() {
try {
- Class> jsonbResolverClass = Class
- .forName("io.quarkus.resteasy.jackson.runtime.QuarkusObjectMapperContextResolver");
- return jsonbResolverClass.newInstance();
+ Class> objectMapperResolverClass = Class
+ .forName("io.quarkus.resteasy.common.runtime.jackson.QuarkusObjectMapperContextResolver");
+ return objectMapperResolverClass.newInstance();
} catch (Exception e) {
throw new RuntimeException(e);
}