Repository: quarkusio/quarkus
Issue: Serialization of RestEasy JAXB wrapped collections fails in native mode

**Describe the bug**

When using the `org.jboss.resteasy.annotations.providers.jaxb.Wrapped` annotation in JAX-RS resource to force a specific Collection wrapping XML tag, the collection it not serialized in native mode. However it works as expected in JVM mode.

I use the following code:
```java
    @GET
    @Produces({MediaType.APPLICATION_JSON, MediaType.TEXT_XML})
    @Wrapped(element="pastries")
    public List<Pastry> getPastries() {
        return PastryRepository.getPastries();
    }
```
**Expected behavior**

When calling my REST endpoint, I expect something like: 

```xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<pastries>
   <pastry><name>Tartelette Fraise</name><price>2.0</price><size>S</size><status>available</status></pastry>
   <pastry><name>Eclair Cafe</name><price>2.5</price><size>M</size><status>available</status></pastry>
   <pastry><name>Millefeuille</name><price>4.4</price><size>L</size><status>available</status></pastry>
</pastries>
```

and that's the result I have when testing in JVM mode.

**Actual behavior**

When running in native mode, I have the following result:

```xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><pastries/>
```

When calling REST endpoint that returns single entity (ex: `/pastry/{name}`), JAXB serialization works as expected even in native mode.

**To Reproduce**
Steps to reproduce the behavior:
1. Create a `Pastry` bean annotated with `@RegisterForReflection` and `@XmlRootElement`
2. Create a JAX-RS `PastryResource` with a method annotated with `@Wrapped(element="pastries")` and returning a List of Pastry
3. Compile your app in native mode and invoke the JAX-RS endpoint.

I have a demo project here: https://github.com/microcks/api-lifecycle/tree/master/api-pastry-demo/api-implementations/quarkus-api-pastry but it already contains the workaround I found (see below). You will have to remove it first for reproducing the failure.

**Configuration**

No properties added.

**Environment:**
 - Output of `uname -a` or `ver`: `Darwin lbroudou1-mac 18.7.0 Darwin Kernel Version 18.7.0: Tue Aug 20 16:57:14 PDT 2019; root:xnu-4903.271.2~2/RELEASE_X86_64 x86_64`
 - Output of `java -version`: `OpenJDK Runtime Environment AdoptOpenJDK (build 11.0.8+10)`
 - GraalVM version (if different from Java): used the docker image for native compilation
 - Quarkus version or git rev: `1.7.1.Final`
 - Build tool (ie. output of `mvnw --version` or `gradlew --version`): `Apache Maven 3.6.3 (cecedd343002696d0abb50b32b541b8a6ba2883f)`

**Workaround**

Found a workaround by adding a `reflection-config.json` file and the adhoc native compilation flag. Once added the annotation is well managed in native mode and the serialization works as expected.

```json
[
  {
    "name" : "org.jboss.resteasy.plugins.providers.jaxb.JaxbCollection",
    "allDeclaredConstructors" : true,
    "allPublicConstructors" : true,
    "allDeclaredMethods" : true,
    "allPublicMethods" : true,
    "allDeclaredFields" : true,
    "allPublicFields" : true
  },
  {
    "name" : "javax.xml.bind.annotation.W3CDomHandler",
    "allDeclaredConstructors" : true,
    "allPublicConstructors" : true,
    "allDeclaredMethods" : true,
    "allPublicMethods" : true,
    "allDeclaredFields" : true,
    "allPublicFields" : true
  }
]
```

I think that this setup should be managed within `resteasy-jaxb` extension as this is a common use-case in RestEasy. If that makes sense for you, I could contribute a PR.


Changed files:
extensions/resteasy-jaxb/deployment/src/test/java/io/quarkus/resteasy/jaxb/deployment/ProducesXMLTestCase.java
extensions/resteasy-jaxb/deployment/src/main/java/io/quarkus/resteasy/jaxb/deployment/ResteasyJaxbProcessor.java

diff --git a/extensions/resteasy-jaxb/deployment/src/main/java/io/quarkus/resteasy/jaxb/deployment/ResteasyJaxbProcessor.java b/extensions/resteasy-jaxb/deployment/src/main/java/io/quarkus/resteasy/jaxb/deployment/ResteasyJaxbProcessor.java
index efa692c91b4..f9492324c8e 100755
--- a/extensions/resteasy-jaxb/deployment/src/main/java/io/quarkus/resteasy/jaxb/deployment/ResteasyJaxbProcessor.java
+++ b/extensions/resteasy-jaxb/deployment/src/main/java/io/quarkus/resteasy/jaxb/deployment/ResteasyJaxbProcessor.java
@@ -1,14 +1,52 @@
 package io.quarkus.resteasy.jaxb.deployment;
 
+import java.lang.annotation.Annotation;
+import java.util.Arrays;
+import java.util.List;
+
+import org.jboss.jandex.DotName;
+import org.jboss.jandex.IndexView;
+import org.jboss.resteasy.annotations.providers.jaxb.Wrapped;
+import org.jboss.resteasy.annotations.providers.jaxb.WrappedMap;
+
 import io.quarkus.deployment.Feature;
 import io.quarkus.deployment.annotations.BuildProducer;
 import io.quarkus.deployment.annotations.BuildStep;
+import io.quarkus.deployment.builditem.CombinedIndexBuildItem;
 import io.quarkus.deployment.builditem.FeatureBuildItem;
+import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem;
 
 public class ResteasyJaxbProcessor {
 
+    private static final List<Class<? extends Annotation>> RESTEASY_JAXB_ANNOTATIONS = Arrays.asList(
+            Wrapped.class,
+            WrappedMap.class);
+
+    @BuildStep
+    void processAnnotations(BuildProducer<ReflectiveClassBuildItem> reflectiveClass,
+            CombinedIndexBuildItem combinedIndexBuildItem) {
+        IndexView index = combinedIndexBuildItem.getIndex();
+
+        // Handle RESTEasy annotations usage.
+        for (Class annotationClazz : RESTEASY_JAXB_ANNOTATIONS) {
+            DotName annotation = DotName.createSimple(annotationClazz.getName());
+
+            if (!index.getAnnotations(annotation).isEmpty()) {
+                addReflectiveClass(reflectiveClass, true, true, "org.jboss.resteasy.plugins.providers.jaxb.JaxbCollection");
+                addReflectiveClass(reflectiveClass, true, true, "org.jboss.resteasy.plugins.providers.jaxb.JaxbMap");
+                addReflectiveClass(reflectiveClass, true, true, "javax.xml.bind.annotation.W3CDomHandler");
+                break;
+            }
+        }
+    }
+
     @BuildStep
     void build(BuildProducer<FeatureBuildItem> feature) {
         feature.produce(new FeatureBuildItem(Feature.RESTEASY_JAXB));
     }
+
+    private void addReflectiveClass(BuildProducer<ReflectiveClassBuildItem> reflectiveClass, boolean methods, boolean fields,
+            String... className) {
+        reflectiveClass.produce(new ReflectiveClassBuildItem(methods, fields, className));
+    }
 }
diff --git a/extensions/resteasy-jaxb/deployment/src/test/java/io/quarkus/resteasy/jaxb/deployment/ProducesXMLTestCase.java b/extensions/resteasy-jaxb/deployment/src/test/java/io/quarkus/resteasy/jaxb/deployment/ProducesXMLTestCase.java
index f1e44da341e..bb04058c164 100644
--- a/extensions/resteasy-jaxb/deployment/src/test/java/io/quarkus/resteasy/jaxb/deployment/ProducesXMLTestCase.java
+++ b/extensions/resteasy-jaxb/deployment/src/test/java/io/quarkus/resteasy/jaxb/deployment/ProducesXMLTestCase.java
@@ -1,11 +1,18 @@
 package io.quarkus.resteasy.jaxb.deployment;
 
+import static org.hamcrest.Matchers.is;
+
+import java.util.Arrays;
+import java.util.List;
+
 import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
 import javax.ws.rs.POST;
 import javax.ws.rs.Path;
 import javax.ws.rs.Produces;
 import javax.ws.rs.core.MediaType;
 
+import org.jboss.resteasy.annotations.providers.jaxb.Wrapped;
 import org.jboss.shrinkwrap.api.ShrinkWrap;
 import org.jboss.shrinkwrap.api.spec.JavaArchive;
 import org.junit.jupiter.api.Assertions;
@@ -34,6 +41,15 @@ public void testProducesXML() {
                 .contentType(MediaType.APPLICATION_XML)
                 .extract().as(Bar.class);
         Assertions.assertEquals(new Bar("open", "bar"), res);
+
+        RestAssured.given()
+                .contentType(ContentType.TEXT)
+                .when().get("/foo")
+                .then()
+                .log().ifValidationFails()
+                .statusCode(200)
+                .contentType(MediaType.APPLICATION_XML)
+                .body("bars.bar.size()", is(2));
     }
 
     @Path("/foo")
@@ -46,6 +62,14 @@ public Bar post(String bar) {
             final String[] s = bar.split(" ");
             return new Bar(s[0], s[1]);
         }
-    }
 
+        @GET
+        @Consumes(MediaType.TEXT_PLAIN)
+        @Produces(MediaType.APPLICATION_XML)
+        @Wrapped(element = "bars")
+        public List<Bar> list() {
+            return Arrays.asList(new Bar("name_1", "description_1"),
+                    new Bar("name_2", "description_2"));
+        }
+    }
 }