Jackson und Java EE 8


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();
    }
}

Über Dominik Mathmann
Dominik Mathmann arbeitet als Berater, Entwickler und Trainer bei der GEDOPLAN GmbH. Auf Basis seiner langjährigen Erfahrung in der Implementierung von Java-EE-Anwendungen leitet er Seminare, hält Vorträge und unterstützt Kunden bei der Konzeption und Realisierung von Webanwendungen vom Backend bis zum Frontend. Sein derzeitiger Schwerpunkt liegt dabei auf der Entwicklung von JSF-Anwendungen. Er sieht die stärker werdende Position von JavaScript-Frameworks jedoch positiv und beschäftigt sich darüber hinaus mit Webframeworks wie Angular.

2 Responses to Jackson und Java EE 8

  1. Marc Dzaebel says:

    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?

    • Dominik Mathmann says:

      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 )

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden /  Ändern )

Google Foto

Du kommentierst mit Deinem Google-Konto. Abmelden /  Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden /  Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden /  Ändern )

Verbinde mit %s

%d Bloggern gefällt das: