diff --git a/core/deployment/src/main/java/io/quarkus/deployment/ConstructorPropertiesProcessor.java b/core/deployment/src/main/java/io/quarkus/deployment/ConstructorPropertiesProcessor.java
new file mode 100644
index 000000000..28bb0d5da
--- /dev/null
+++ b/core/deployment/src/main/java/io/quarkus/deployment/ConstructorPropertiesProcessor.java
@@ -0,0 +1,42 @@
+package io.quarkus.deployment;
+
+import org.jboss.jandex.AnnotationInstance;
+import org.jboss.jandex.AnnotationTarget;
+import org.jboss.jandex.DotName;
+import org.jboss.jandex.IndexView;
+import org.jboss.jandex.MethodInfo;
+
+import io.quarkus.deployment.annotations.BuildProducer;
+import io.quarkus.deployment.annotations.BuildStep;
+import io.quarkus.deployment.builditem.CombinedIndexBuildItem;
+import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem;
+
+/**
+ * Registers all classes for reflection,
+ * that contain a constructor annotated with @java.beans.ConstructorProperties.
+ */
+public class ConstructorPropertiesProcessor {
+
+ private static final DotName CONSTRUCTOR_PROPERTIES = DotName.createSimple("java.beans.ConstructorProperties");
+
+ @BuildStep
+ void build(BuildProducer reflectiveClass, CombinedIndexBuildItem indexBuildItem) {
+ IndexView index = indexBuildItem.getIndex();
+ for (AnnotationInstance annotationInstance : index.getAnnotations(CONSTRUCTOR_PROPERTIES)) {
+ registerInstance(reflectiveClass, annotationInstance);
+ }
+ }
+
+ private void registerInstance(BuildProducer reflectiveClass, AnnotationInstance instance) {
+ AnnotationTarget annotationTarget = instance.target();
+ if (annotationTarget instanceof MethodInfo) {
+ MethodInfo methodInfo = (MethodInfo) annotationTarget;
+ String classname = methodInfo.declaringClass().toString();
+ reflectiveClass.produce(asReflectiveClassBuildItem(classname));
+ }
+ }
+
+ private ReflectiveClassBuildItem asReflectiveClassBuildItem(String annotatedClass) {
+ return new ReflectiveClassBuildItem(true, false, annotatedClass);
+ }
+}
diff --git a/integration-tests/main/src/main/java/io/quarkus/it/rest/TestResourceForConstructorProperties.java b/integration-tests/main/src/main/java/io/quarkus/it/rest/TestResourceForConstructorProperties.java
new file mode 100644
index 000000000..6550a7886
--- /dev/null
+++ b/integration-tests/main/src/main/java/io/quarkus/it/rest/TestResourceForConstructorProperties.java
@@ -0,0 +1,86 @@
+package io.quarkus.it.rest;
+
+import java.beans.ConstructorProperties;
+
+import javax.json.bind.JsonbBuilder;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.sse.OutboundSseEvent;
+import javax.ws.rs.sse.Sse;
+import javax.ws.rs.sse.SseEventSink;
+
+@Path("/constructorproperties")
+public class TestResourceForConstructorProperties {
+
+ @Context
+ Sse sse;
+
+ @GET
+ @Path("/direct")
+ @Produces(MediaType.APPLICATION_JSON)
+ public VanillaJavaImmutableData direct() {
+ return new VanillaJavaImmutableData("direct", "directvalue");
+ }
+
+ @GET
+ @Path("/jsonb")
+ @Produces(MediaType.APPLICATION_JSON)
+ public String jsonb() {
+ VanillaJavaImmutableData entity = new VanillaJavaImmutableData("jsonb", "jsonbvalue");
+ return JsonbBuilder.create().toJson(entity);
+ }
+
+ @GET
+ @Path("/response")
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response response() {
+ VanillaJavaImmutableData entity = new VanillaJavaImmutableData("response", "responsevalue");
+ return Response.ok(entity).build();
+ }
+
+ @GET
+ @Path("/sse")
+ @Produces(MediaType.SERVER_SENT_EVENTS + ";element-type=" + MediaType.APPLICATION_JSON)
+ public void serverSentEvents(@Context SseEventSink sink) {
+ VanillaJavaImmutableData data = new VanillaJavaImmutableData("sse", "ssevalue");
+ try {
+ OutboundSseEvent.Builder builder = sse.newEventBuilder();
+ builder.id(String.valueOf(1))
+ .mediaType(MediaType.APPLICATION_JSON_TYPE)
+ .data(data)
+ .name("stream of json data");
+
+ sink.send(builder.build());
+ } finally {
+ sink.close();
+ }
+ }
+
+ public static class VanillaJavaImmutableData {
+ private final String name;
+ private final String value;
+
+ @ConstructorProperties({ "name", "value" })
+ public VanillaJavaImmutableData(String name, String value) {
+ this.name = name;
+ this.value = value;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ @Override
+ public String toString() {
+ return "ConstructorPropertiesAnnotatedImmutableData [name=" + name + ", value=" + value + "]";
+ }
+ }
+}
diff --git a/integration-tests/main/src/test/java/io/quarkus/it/main/JaxRsConstructorPropertiesITCase.java b/integration-tests/main/src/test/java/io/quarkus/it/main/JaxRsConstructorPropertiesITCase.java
new file mode 100644
index 000000000..99ef598a1
--- /dev/null
+++ b/integration-tests/main/src/test/java/io/quarkus/it/main/JaxRsConstructorPropertiesITCase.java
@@ -0,0 +1,8 @@
+package io.quarkus.it.main;
+
+import io.quarkus.test.junit.NativeImageTest;
+
+@NativeImageTest
+public class JaxRsConstructorPropertiesITCase extends JaxRsConstructorPropertiesTestCase {
+
+}
diff --git a/integration-tests/main/src/test/java/io/quarkus/it/main/JaxRsConstructorPropertiesTestCase.java b/integration-tests/main/src/test/java/io/quarkus/it/main/JaxRsConstructorPropertiesTestCase.java
new file mode 100644
index 000000000..a00a64f7b
--- /dev/null
+++ b/integration-tests/main/src/test/java/io/quarkus/it/main/JaxRsConstructorPropertiesTestCase.java
@@ -0,0 +1,44 @@
+package io.quarkus.it.main;
+
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.is;
+
+import org.junit.jupiter.api.Test;
+
+import io.quarkus.test.junit.QuarkusTest;
+import io.restassured.RestAssured;
+import io.restassured.specification.RequestSender;
+
+@QuarkusTest
+public class JaxRsConstructorPropertiesTestCase {
+
+ @Test
+ public void testReturnedDirectly() {
+ when().get("/constructorproperties/direct").then()
+ .body("name", is("direct"),
+ "value", is("directvalue"));
+ }
+
+ @Test
+ public void testConvertedWithJsonbAndReturnedAsString() {
+ when().get("/constructorproperties/jsonb").then()
+ .body("name", is("jsonb"),
+ "value", is("jsonbvalue"));
+ }
+
+ @Test
+ public void testWrappedInResponse() {
+ when().get("/constructorproperties/response").then()
+ .body("name", is("response"),
+ "value", is("responsevalue"));
+ }
+
+ @Test
+ public void testWrappedInServerSentEventMessage() {
+ when().get("/constructorproperties/sse").then().body(containsString("ssevalue"));
+ }
+
+ private static RequestSender when() {
+ return RestAssured.when();
+ }
+}