Jackson ist eine Bibliothek die sich unter anderem darum kümmert das unsere Businessobjekte in JSON umgewandelt werden. Als default Provider für diese Aufgabe war Jackson bisher im Wildfly Application Server vorhanden. Seit Java EE 8 (und Wildfly 13) gibt es nun einen neuen Standard der sich um diese Aufgabe kümmert: JSON-B. Dieser ist leider in Sachen Funktionsumfang bei weitem noch nicht auf den Stand den Jackson erreicht hat. Um Jackson weiterhin zu nutzen sind (leider) einige Schritte von nöten
Laut Spezifikation von JAX-RS reicht es aus eine @Provider-Klasse an zu bieten welche für einen bestimmten Media Type die Konvertierung unserer Businessobjekte übernimmt. Diesen liefert Jackson mit einer entsprechenden Maven Dependency praktischerweise gleich mit (com.fasterxml.jackson.jaxrs, jackson-jaxrs-json-provider ). Schade nur das es bei dieser Theorie bleibt. Zumindest der Wildfly 13 (im EE8 Profil) und der Glassfish 5 weigern sich dieses einfache Vorgehen mit Erfolg zu krönen.
Wildfly 13
Ein Bug in RestEasy (RESTEASY-1911 ) verhindert hier das Jackson korrekt eingebunden wird. Ab der Version 3.6 soll dieser Umstand behoben sein, bis dahin hilft der Ausschluss des Resteasy Json Providers:
<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.0"> <jdeployment> <jexclusions> <jmodule name="org.jboss.resteasy.resteasy-json-binding-provider"><j/module> <j/exclusions> <j/deployment> <j/jboss-deployment-structure>
src/main/webapp/WEB-INF/jboss-deployment-structure.xml
Glassfish 5
Die Referenzimplementierung für Java EE 8 ist hartnäckig was das Ersetzen von JSON-B als JSON Provider angeht. Hier ist ein zusätzlicher Konfigurationsparamter notwenig:
@ApplicationPath("resources") public class ApplicationConfig extends Application { @Override public Map getProperties() { Map proprties = new HashMap(); proprties.put("jersey.config.server.disableMoxyJson", true); //Glassfish = 5 return proprties; } }
Optional: globaler ObjectMapper
Jacksons ObjectMapper bietet eine ganze Reihe von globalen Einstellungen um das Verhalten beim Parsen von JSON-Strukturen zu beeinflussen (Format, Umgang mit null-Werten und unbekannter Attribute…). Um in der gesamten Anwendung eine einheitliche Konfiguration zu verwenden bietet sich ein entsprechner CDI Producer an:
@ApplicationScoped public class GlobalCDIProducer { private ObjectMapper mapper; @Produces public ObjectMapper getMapper(){ if(this.mapper==null){ this.mapper=new ObjectMapper(); DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm"); this.mapper.setDateFormat(df); } return this.mapper; } }
Diesen können wir natürlich selber in unseren Resouce-Klassen injizieren und Verwenden, aber auch JAX-RS zur Verfügung stellen:
@Provider public class JacksonProvider implements ContextResolver<ObjectMapper> { @Inject private ObjectMapper mapper; @Override public ObjectMapper getContext(Class<?> type) { return getMapper(); } }
2 Kommentare. Hinterlasse eine Antwort
Danke, das ist sicher für viele hilfreich, die nicht einfach umstellen können. Allerdings ist JSON-P 1.1 und JSON-Bind 1.0 ein sinnvoller Kompromiss, den man auch nutzen sollte. Wir brauchen solche Standards für Interoperabilität in heterogenen Servicelandschaften. Mich würde interessieren, welche wichtigen Features nicht in der Referenzimplementierung abgedeckt sind?
Das ist völlig richtig: die Nutzung eines Standards würde ich hier immer vorziehen. Standard des Standards willen ist für mich aber kaum eine praktikable Lösung, am Ende des Tages geht es für mich auch darum stabile und wartbare Software zu schreiben mit einem angemessenen Aufwand. Wenn ich dafür auf Bibliotheken zurückgreifen muss die nicht dem Standard unterworfen sind nehme ich das gerne in Kauf.
Im Fall von JSON-B ist man sicherlich auf dem richtigen Weg und ich hoffe das hier noch ein paar Handschläge getan werden. Die grundlegenden Funktionen sind ja auch bereits alle zu finden, in den Feinheiten merkt man meiner Meinung allerdings das Bibliotheken wie „Jackson“ schon wesentlich länger gereift sind: um nur mal zwei Features zu nennen die in Jackson zur Verfügung stehen und in JSON-B fehlen oder sich wesentlich unflexbiler einsetzen lassen: JsonViews (fehlt leider in dieser einfachen Form im neuen Standard). Zweites Resolver (https://javaeeblog.wordpress.com/2018/06/29/jpa-rest-jackson-resolver/ ) , so etwas lässt sich leider derzeit aus meiner Sicht ebenfalls nicht mit einem einzigen generischen Resolver in JsonB lösen ( weil die Möglichkeit der Scope- / Ziel-Klassen nicht unterstützt wird, was dazu führt das wir für jede Entity eine eigene konkrete Resolver Klassen benötigen )