# Wildfly - JAXB und JsonB gemeinsam nutzen



## mrBrown (13. Jul 2019)

Ich hab aktuell in Problem mit der Serialisierung von Klassen als XML und Json, vielleicht kennt sich jemand zufällig damit aus.

Ich hab eine einfache Jax-rs-Applikation, die einfach nur ein simples DTO zurückgibt.
Das DTO ist annotiert mit JAXB und JsonB-Annotationen (zB, da Adapter aus beiden APIs benutzt werden).
Die Serialisierung als XML klappt problemlos, die Serialisierung als Json allerdings nicht.
Statt Json-B zu nutzen, nutzt er (wenn ich’s richtig sehe) Jackson und serialisiert das ganze anhand der JAXB-Annotationen, welches zB bei Nutzung der Adapter fehlschlägt. Lässt man die JAXB-Annotationen weg, wird passend mit JsonB serialisiert, dann scheitert aber natürlich JAXB...


Probiert hab ich bisher, Jackson explizit zu ignorieren (findet dann gar keinen MessageBody-Writer für Json), und die Klasse mit @NoJackson bzw @IgnoreMediaTypes zu annotieren, hat aber bisher nichts gebracht.


Hat vielleicht irgendjemand eine Idee?


----------



## mihe7 (13. Jul 2019)

mrBrown hat gesagt.:


> Hat vielleicht irgendjemand eine Idee?


Nicht, dass ich das schon mal gemacht hätte, aber https://github.com/devcon5io/jackson-jsonb-provider könnte etwas sein.


----------



## mrBrown (13. Jul 2019)

mihe7 hat gesagt.:


> Nicht, dass ich das schon mal gemacht hätte, aber https://github.com/devcon5io/jackson-jsonb-provider könnte etwas sein.


Klappt leider nicht, das stellt Jackson nur als Jsonb zur Verfügung, unterstützt aber trotzdem die Spec und die Annotation nicht :/


----------



## mihe7 (13. Jul 2019)

mrBrown hat gesagt.:


> Klappt leider nicht, das stellt Jackson nur als Jsonb zur Verfügung, unterstützt aber trotzdem die Spec und die Annotation nicht


Hm... kannst Du nicht zusätzlich z. B. Yasson verwenden?


----------



## mrBrown (13. Jul 2019)

Das wird im Wildfly genutzt - aber das Problem ist ja eben, dass es bei mir nur genutzt wird, wenn in der Klasse keinerlei JAXB-Annotationen vorhanden sind.




```
class TestDto {
  @JsonbProperty("jsonb-id")
  public String id = "id";
}
```
Führt zu 
	
	
	
	





```
{
    "json-id": "id"
}
```


Aber 

```
@XmlRootElement(name = "test")
class TestDto {
  @XmlAttribute(name = "xml-id")
  @JsonbProperty("jsonb-id")
  public String id = "id";
}
```
Führt zu 
	
	
	
	





```
{
    "xml-id": "id"
}
```




Spoiler: Application & Resource





```
@ApplicationPath("")
public class AppConfig extends Application {

}
```


```
@Path("test")
public class TestResource {
    @GET
    @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
    public TestDto getTest() {
        return new TestDto();
    }
}
```


----------



## mihe7 (13. Jul 2019)

Hm... hab das mal in Payara Micro probiert: 
Class org.eclipse.yasson.internal.model.GetFromField can not access a member of class app.TestDto with modifiers "public"

XML funktioniert. Strange.


----------



## mrBrown (13. Jul 2019)

mihe7 hat gesagt.:


> Class org.eclipse.yasson.internal.model.GetFromField can not access a member of class app.TestDto with modifiers "public"


Oh, die Klasse sollte public sein, dann gehts.


Aber halt nur in Payara Micro...


----------



## mihe7 (13. Jul 2019)

mrBrown hat gesagt.:


> Oh, die Klasse sollte public sein,


Mein Gott, bin ich blind.



mrBrown hat gesagt.:


> Aber halt nur in Payara Micro...


Man muss sich ja langsam rantasten


----------



## mihe7 (13. Jul 2019)

Hm... verstehe ich hier was falsch, oder ist das Müll?

"A JAXB Provider is selected by RESTEasy when a parameter or return type is an object that is annotated with JAXB annotations (such as @XmlRootEntity or @XmlType) or if the type is a JAXBElement." (https://docs.jboss.org/resteasy/doc...tml_single/index.html#Built_in_JAXB_providers)


----------



## mrBrown (13. Jul 2019)

Das sollte sich allerdings mit @IgnoreMediaTypes ignorierbar sein:





			
				https://docs.jboss.org/resteasy/docs/3.6.0.Final/userguide/html_single/index.html#Possible_Jackson_Problems hat gesagt.:
			
		

> If your Jackson classes are annotated with JAXB annotations and you have the resteasy-jaxb-provider in your classpath, you may trigger the Jettision JAXB marshalling code. To turn off the JAXB json marshaller use the @org.jboss.resteasy.annotations.providers.jaxb.IgnoreMediaTypes("application/*+json") on your classes.



Und Json-B sollte zumindest meinem Verständnis trotzdem Vorrang haben: 





			
				https://docs.jboss.org/resteasy/docs/3.6.0.Final/userguide/html_single/index.html#d4e1500 hat gesagt.:
			
		

> To satisfy JAX-RS 2.1 requirements, JsonBindingProvider takes precedence over the other providers for dealing with JSON payloads, in particular the Jackson one.



Vielleicht gibts da noch irgendwelche geheimen Flags die man kennen muss...


----------



## mihe7 (13. Jul 2019)

Für meine Begriffe ist das schlicht ein Bug... Ah: https://issues.jboss.org/browse/RESTEASY-2158


----------



## mrBrown (14. Jul 2019)

Du bist genial...ich hab gefühlt ewig nach nem issue dazu gesucht.

Scheint leider erst in Resteasy 4 geändert zu sein, aber lässt sich sicher auch in unsere Version lokal irgendwie patchen...


----------



## mihe7 (14. Jul 2019)

mrBrown hat gesagt.:


> Du bist genial...ich hab gefühlt ewig nach nem issue dazu gesucht.


Eigentlich merke ich immer mehr, wie viel ich nicht weiß 



mrBrown hat gesagt.:


> aber lässt sich sicher auch in unsere Version lokal irgendwie patchen...


Jo....

Mit


Spoiler: Patch





```
diff --git a/providers/json-binding/src/main/java/org/jboss/resteasy/plugins/providers/jsonb/JsonBindingProvider.java b/providers/json-binding/src/main/java/org/jboss/resteasy/plugins/providers/jsonb/JsonBindingProvider.java
index b4cc73d..b2b5559 100644
--- a/providers/json-binding/src/main/java/org/jboss/resteasy/plugins/providers/jsonb/JsonBindingProvider.java
+++ b/providers/json-binding/src/main/java/org/jboss/resteasy/plugins/providers/jsonb/JsonBindingProvider.java
@@ -20,11 +20,6 @@ import javax.ws.rs.core.MultivaluedMap;
 import javax.ws.rs.ext.MessageBodyReader;
 import javax.ws.rs.ext.MessageBodyWriter;
 import javax.ws.rs.ext.Provider;
-import javax.xml.bind.JAXBElement;
-import javax.xml.bind.annotation.XmlRootElement;
-import javax.xml.bind.annotation.XmlSeeAlso;
-import javax.xml.bind.annotation.XmlType;
-import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
 
 import org.apache.commons.io.input.ProxyInputStream;
 import org.jboss.resteasy.plugins.providers.jsonb.i18n.Messages;
@@ -60,12 +55,7 @@ public class JsonBindingProvider extends AbstractJsonBindingProvider
       {
          return false;
       }
-      if (isGenericJaxb(type, genericType))
-      {
-         return false;
-      }
-      return (isSupportedMediaType(mediaType))
-              && ((FindAnnotation.hasJsonBindingAnnotations(annotations)) || (!isJaxbClass(type)));
+      return isSupportedMediaType(mediaType);
    }
 
    @Override
@@ -119,12 +109,7 @@ public class JsonBindingProvider extends AbstractJsonBindingProvider
       {
          return false;
       }
-      if (isGenericJaxb(type, genericType))
-      {
-         return false;
-      }
-      return (isSupportedMediaType(mediaType))
-            && ((FindAnnotation.hasJsonBindingAnnotations(annotations)) || (!isJaxbClass(type)));
+      return isSupportedMediaType(mediaType);
    }
 
    @Override
@@ -150,42 +135,4 @@ public class JsonBindingProvider extends AbstractJsonBindingProvider
       }
    }
    
-   private boolean isGenericJaxb(Class<?> type, Type genericType)
-   {
-      if (Map.class.isAssignableFrom(type) && genericType != null)
-      {
-         Class<?> valueType = Types.getMapValueType(genericType);
-         if (valueType != null && isJaxbClass(valueType))
-         {
-            return true;
-         }
-      }
-
-      if ((Collection.class.isAssignableFrom(type) || type.isArray()) && genericType != null)
-      {
-         Class<?> baseType = Types.getCollectionBaseType(type, genericType);
-         if (baseType != null && isJaxbClass(baseType))
-         {
-            return true;
-         }
-      }
-      return false;
-   }
-
-   private boolean isJaxbClass(Class<?> classType)
-   {
-      if (JAXBElement.class.equals(classType))
-      {
-         return true;
-      }
-      for (Annotation a : classType.getAnnotations()) {
-         Class<? extends Annotation> c = a.annotationType();
-         if (c.equals(XmlRootElement.class) || c.equals(XmlType.class) ||c.equals(XmlJavaTypeAdapter.class) ||c.equals(XmlSeeAlso.class))
-         {
-            return true;
-         }
-      }
-      return false;
-
-   }
 }
```



liefern

```
curl -H "Accept: application/xml" http://localhost:8080/jpa/test
vs
curl -H "Accept: application/json" http://localhost:8080/jpa/test
```
die Ausgaben

```
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><test xml-id="id"/>
vs
{"jsonb-id":"id"}
```


----------

