Working with JSON in Java RESTful Services using Jackson

Since a long time the Java Script Object Notation [1] become as a lightweight standard to replace XML for information exchange between heterogeneous systems. Both technologies XML and JSON closed those gap to return simple and complex data of a remote method invocation (RMI), when different programming languages got involved. Each of those technologies has its own benefits and disadvantages. A good designed XML document is human readable but needs in comparing to JSON more payload when it send through the network. For almost every programming languages existing plenty implementations to deal with XML and also JSON. We don’t need to reinvent the wheel, to implement our own solution for handling JSON objects. But choosing the right library is not that easy might it seems.

The most popular library for JSON in Java projects is the one I already mentioned: Jackson [2]. because of its huge functionality. Another important point for choosing Jackson instead of other libraries is it’s also used by the Jersey REST Framework [3]. Before we start now our journey with the Java Frameworks Jersey and Jackson, I like to share some thoughts about things, I often observe in huge projects during my professional life. Because of this reason I always proclaim: don’t mix up different implementation libraries for the same technology. The reason is it’s a huge quality and security concern.

The general purpose for using JSON in RESTful applications is to transmit data between a server and a client via HTTP. To achieve that, we need to solve two challenges. First, on the server side, we need create form a Java object a valid JSON representation which we can send to the client. This process we call serialization. On the client side, we do the second step, which is exactly the opposite, we did on the server. De-serialization we call it, when we create a valid object from a JSON String.

In this article we will use on the server side and also on the client side Java as programming language, to deal with JSON objects. But keep in mind REST allows you to have different programming languages on the server and for the client. Java is always a good choice to implement your business logic on the server. The client side often is made with JavaScript. Also PHP, .NET and other programming Languages are possible.

In the next step we will have a look at the project architecture. All artifacts are organized by one Apache Maven Multi-Module project. It’s a good recommendation to follow this structure in your own projects too. The three artifacts we create are: api, server and client.

  • API: contain shared objects which will needed on the server and also client side, like domain objects and interfaces.
  • Server: producer of a RESTful service, depends on API.
  • Client: consumer of the RESTful service, depends on API.

Inside of this artifacts an layer architecture is applied. This means the access to objects from a layer is only allowed to the direction of the underlying layers. In short: from top to down. The layer structure are organized by packages. Not every artifact contains every layer, only the ones which are implemented. The following picture draws an better understanding for the whole architecture is used.

The first piece of code, I’d like to show are the JSON dependencies we will need in the notation for Maven projects.

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>${version}</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-annotations</artifactId>
    <version>${version}</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>${version}</version>
</dependency>

Listing 1

In respect to the size of this article, I only focus how the JSON object is used in RESTful applications. It’s not a full workshop about RESTful (Micro) Services. As code base we reuse my open source GitHub project TP-ACL [4], an access control list. For our example I decided to sliced apart the Role – Functionality from the whole code base.

For now we need as first an Java object which we can serialize to an JSON String. This Domain Object will be the Class RolesDO and is located in the layer domain inside the API module. The roles object contains a name, a description and a flag that indicates if a role is allowed to delete.

@Entity
@Table(name = "ROLES")
public class RolesDO implements Serializable {

    private static final long serialVersionUID = 50L;

    @Id
    @Column(name = "NAME")
    private String name;

    @Column(name = "DESCRIPTION")
    private String description;

    @Column(name = "DELETEABLE")
    private boolean deleteable;

    public RolesDO() {
        this.deleteable = true;
    }

    public RolesDO(final String name) {
        this.name = name;
        this.deleteable = true;
    }

    //Getter & Setter
}

Listing 2

So far so good. As next step we will need to serialize the RolesDO in the server module as a JSON String. This step we will do in the RolesHbmDAO which is stored in the implementation layer within the Server module. The opposite direction, the de-serialization is also implemented in the same class. But slowly, not everything at once. lets have as first a look on the code.

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

public class RolesDAO {

    public transient EntityManager mainEntityManagerFactory;

    public String serializeAsJson(final RolesDO role) 
            throws JsonProcessingException {
        ObjectMapper mapper = new ObjectMapper();
        return mapper.writeValueAsString(role);
    }

    public RolesDO deserializeJsonAsObject(final String json, final RolesDO role) 
            throws JsonProcessingException, ClassNotFoundException {
        ObjectMapper mapper = new ObjectMapper();
        return (RolesDO) mapper.readValue(json, Class.forName(object.getCanonicalName()));
    }

    public List<RolesDO> deserializeJsonAsList(final String json)
            throws JsonProcessingException, ClassNotFoundException {       
        ObjectMapper mapper = new ObjectMapper();
        return mapper.readValue(json, new TypeReference<List>() {});
    }

    public List listProtectedRoles() {

        CriteriaBuilder builder = mainEntityManagerFactory.getCriteriaBuilder();
        CriteriaQuery query = builder.createQuery(RolesDO.class);
        
        Root root = query.from(RolesDO.class);
        query.where(builder.isNull(root.get("deactivated")));
        query.orderBy(builder.asc(root.get("name")));

        return mainEntityManagerFactory.createQuery(query).getResultList();
    }
}

Listing 3

The implementation is not so difficult to understand, but may at this point could the first question appear. Why the de-serilization is in the server module and not in the client module? When the client sends a JSON to the server module, we need to transform this to an real Java object. Simple as that.

Usually the Data Access Object (DAO) Pattern contains all functionality for database operations. This CRUD (create, read, update and delete) functions, we will jump over. If you like to get to know more about how the DAO pattern is working, you could also check my project TP-CORE [4] at GitHub. Therefore we go ahead to the REST service implemented in the object RoleService. Here we just grep the function fetchRole().

@Service
public class RoleService {

    @Autowired
    private RolesDAO rolesDAO;

    @GET
    @Path("/{role}")
    @Produces({MediaType.APPLICATION_JSON})
    public Response fetchRole(final @PathParam("role") String roleName) {
        Response response = null;
        try {
            RolesDO role = rolesDAO.find(roleName);
            if (role != null) {
                String json = rolesDAO.serializeAsJson(role);
                response = Response.status(Response.Status.OK)
                        .type(MediaType.APPLICATION_JSON)
                        .entity(json)
                        .encoding("UTF-8")
                        .build();
            } else {
                response = Response.status(Response.Status.NOT_FOUND).build();
            }

        } catch (Exception ex) {
            LOGGER.log("ERROR CODE 500 " + ex.getMessage(), LogLevel.DEBUG);
            response = Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
        }
        return response;
    }
}

Listing 4

The big secret here we have in the line where we stick the things together. As first the RolesDO is created and in the next line the DAO calls the serializeAsJson() Method with the RoleDO as parameter. The result will be a JSON representation of the RoleDO. If the role exist and no exceptions occur, then the service is ready for consuming. In the case of any problem the service send a HTTP error code instead of the JSON.

Complex Services which combine single services to a process take place in the orchestration layer. At this point we can switch to the client module to learn how the JSON String got transformed back to a Java domain object. In the client we don’t have RolesHbmDAO to use the deserializeJsonAsObject() method. And of course we also don’t want to create duplicate code. This forbids us to copy paste the function into the client module.

As pendant to the fetchRole() on the server side, we use for the client getRole(). The purpose of both implementations is identical. The different naming helps to avoid confusions.

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;

public class Role {
    private final String API_PATH
            = "/acl/" + Constraints.REST_API_VERSION + "/role";
    private WebTarget target;

    public RolesDO getRole(String role) throws JsonProcessingException {
        Response response = target
                .path(API_PATH).path(role)
                .request()
                .accept(MediaType.APPLICATION_JSON)
                .get(Response.class);
        LOGGER.log("(get) HTTP STATUS CODE: " + response.getStatus(), LogLevel.INFO);

        ObjectMapper mapper = new ObjectMapper();
        return mapper.readValue(response.readEntity(String.class), RolesDO.class);
    }
}

Listing 5

As conclusion we have now seen the serialization and de-serialisation by using the Jackson library of JSON objects is not that difficult. In the most of the cases we just need three methods:

  • serialize a Java object to a JSON String
  • create a Java object from a JSON String
  • de-serialize a list of objects inside a JSON String to a Java object collection

This three methods I already introduced in Listing 2 for the DAO. To prevent duplicate code we should separte those functionality in an own Java Class. This is known as the design pattern Wrapper [5] also known as Adapter. For reaching the best flexibility I implemented the JacksonJsonTools from TP-CORE as Generic.

package org.europa.together.application;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.core..JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.List;

public class JacksonJsonTools {

    private static final long serialVersionUID = 15L;

    public String serializeAsJsonObject(final T object)
            throws JsonProcessingException {
        try {
            ObjectMapper mapper = new ObjectMapper();
            return mapper.writeValueAsString(object);
        } catch (JsonProcessingException ex) {
            System.err.println(ex.getOriginalMessage());
        }
    }

    public T deserializeJsonAsObject(final String json, final Class object)
            throws JsonProcessingException, ClassNotFoundException {
        try {
            Class<?> clazz = Class.forName(object.getCanonicalName());
            ObjectMapper mapper = new ObjectMapper();
            return (T) mapper.readValue(json, clazz);
        } catch (JsonProcessingException ex) {
            System.err.println(ex.getOriginalMessage());
        }
    }

    public List deserializeJsonAsList(final String json)
            throws JsonProcessingException, ClassNotFoundException {
        try {
            ObjectMapper mapper = new ObjectMapper();
            return mapper.readValue(json, new TypeReference<List>() {
            });
        } catch (com.fasterxml.jackson.core.JsonProcessingException ex) {
            System.err.println(ex.getOriginalMessage());
        }
    }
}

Listing 6

This and much more useful Implementations with a very stable API you find in my project TP-CORE for free usage.

Resources:
[1] https://www.json.org/json-en.html
[2] https://github.com/FasterXML/jackson
[3] https://eclipse-ee4j.github.io/jersey/
[4] https://github.com/ElmarDott/TP-CORE/wiki/%5BCORE-02%5D-generic-Data-Access-Object—DAO
[5] https://en.wikipedia.org/wiki/Adapter_pattern

IT-Tage 2022 remote

Refactoring – Eine kurze Geschichte des Scheiterns

Für mein kleines Open Source-Projekt TP-CORE, das Sie auf GitHub finden können, hatte ich die großartige Idee, die iText-Bibliothek für OpenPDF zu ersetzen. Nachdem ich einen Plan gemacht hatte, wie ich mein Ziel erreichen könnte, startete ich alle notwendigen Aktivitäten. Aber im wirklichen Leben sind die Dinge nie so einfach, wie wir es uns ursprünglich vorgestellt haben. In diesem Vortrag erfahren Sie was genau passiert ist. Ich spreche über meine Motivation, warum ich die Änderung wollte und wie mein Plan war, alle Aktivitäten zum Erfolg zu führen. Sie werden erfahren wie es war, als ich den Punkt erreichte bei dem mir klar wurde, dass ich so nicht zum Ziel gelange. Ich erkläre kurz, was ich getan habe, dass dieses kurze Abenteuer den Rest des Projekts nicht beeinflusst hat.

Slides: https://speakerdeck.com/elmardott/refactoring-eine-kurze-geschichte-des-scheiterns

DevOps – Praxistraining – Entwicklung, Test, Monitoring und Logging

Schulung / Training / Kurs / Seminar – 3 Tage remote

Wenn ein Unternehmen sich entscheidet, Software nach der DevOps-Philosophie zu entwickeln, bietet sich eine große Chance, den Kunden robustere Software in kürzeren Entwicklungszyklen bereit zu stellen. Gemeinsam müssen alle Beteiligten die Unternehmenskultur so verändern, dass Konzeption, Entwicklung, Test und Betrieb von Software Hand in Hand gehen.

Für Entwickler bedeutet dies meist eine deutliche Erweiterung von Anforderungen und Verantwortung: Themen wie Containerisierung, Integrationstests, Monitoring und Logging sollten bedacht und beherrscht werden. In diesem Praxisseminar machen Sie sich anhand ‘echter’ Softwareprojekte mit vielen unterschiedlichen Technologien und Methoden vertraut.

Durchführungs-Garantie: der Kurs wird auch bei nur einem Teilenmenden durchgeführt

Kurs buchen: https://www.gfu.net/seminare-schulungen-kurse/java_sk5/devops-werkzeugkasten-entwickler_s2137.html

Jeder Teilenmende erhält eine gedruckte Ausgabe des Buches: Marco Schulz, CI mit Jenkins, Rheinwerk, 2021

Sollten Sie zu den angebotenen Terminen nicht können, beziehungsweise für Ihr Team einen individuellen Termin wünschen, um beispielsweise in einer geschlossenen Runde auf konkrete Problemstellungen eingehen zu können, besteht die Möglichkeit zusätzliche außerplanmäßige Termine zu vereinbaren. Nutzen Sie bitte hierzu mein Kontaktformular unter der Angabe welchen Kurs Sie wünschen, mit Terminvorschlägen und der zu erwartenden Teilnehmerzahl.

Weitere Termine:

  • 27.03 – 29.03.2023 (KW 13)
  • 26.06 – 28.06.2023 (KW 26)
  • 25.09 – 27.09.2023 (KW 39)
  • 11.12 – 13.12.2023 (KW 50)

Maven: Überblick für Entwickler

Schulung / Training / Kurs / Seminar – 1 Tag remote

Apache Maven ist seit mehr als einem Jahrzehnt als Build– und Reporting-Tool für Java-Projekte etabliert. Der Erfolg dieses Werkzeuges begründete sich vor allem in der einfacheren Lösung des Abhängigkeitsmanagements fremder Programmbibliotheken. Entwickler lassen in ihren Projekten mehrmals täglich lokale Maven Builds laufen, wissen aber oft nicht, wie sie bei Problemen Abhilfe schaffen können.

In diesem Workshop lernen Sie die wichtigsten Grundlagen zu Maven kennen. Schnell gehen wir zu fortgeschrittenen Themen über und lernen wie der Build Lifecycle nicht nur über die Build Logik, sondern auch über die Kommandozeile beeinflusst werden kann. Es handelt sich um einen praxis-orientierten Workshop mit vielen Beispielen aus dem Entwickleralltag.

Durchführungs-Garantie: der Kurs wird auch bei nur einem Teilenmer:in durchgeführt.

Kurs buchen: https://www.gfu.net/seminare-schulungen-kurse/testmanagement_sk92/maven-ueberblick-fuer-entwickler_s2345.html

Jede(r) Teilnehmer(in) erhält eine gedruckte Ausgabe des Buches: Marco Schulz, CI mit Jenkins, Rheinwerk, 2021

Sollten Sie zu den angebotenen Terminen nicht können, beziehungsweise für Ihr Team einen individuellen Termin wünschen, um beispielsweise in einer geschlossenen Runde auf konkrete Problemstellungen eingehen zu können, besteht die Möglichkeit zusätzliche außerplanmäßige Termine zu vereinbaren. Nutzen Sie bitte hierzu mein Kontaktformular unter der Angabe welchen Kurs Sie wünschen, mit Terminvorschlägen und der zu erwartenden Teilnehmerzahl.

Weitere Termine:

  • 14.02.2023 (KW 07)
  • 31.05.2023 (KW 22)
  • 30.08.2023 (KW 35)
  • 29.11.2023 (KW 48)

DevOps – Automatisierung in der Java Software Entwicklung

Schulung / Training / Kurs / Seminar – 3 Tage remote

Das Thema DevOps umfasst viele Facetten. Ein zentraler Punkt ist hierbei die Automatisierung. Um im Unternehmen erfolgreich eine DevOps Kultur einführen zu können benötigen die Entwicklungsteams auch eine entsprechende Infrastruktur, die zuverlässig den aktuellen Entwicklungsstand im Projekt offenlegt. Sämtliche Beispiele sind für Projekte auf der Java Infrastruktur ausgelegt.

In diesem Kurs lernen Sie die verschieden Aspekte der Prozessautomatisierung und die zugehörigen Werkzeuge kennen. Sie erfahren praxiserprobte Details über Strategien, mit der Sie schonend aktuelle Projekte in eine DevOps Kultur möglichst Ressourcen schonend überführen können. Dabei liegt der Fokus vornehmlich auf dem Bereich Entwicklung und ist besonders auf die klassischen Arbeitsbereiche des Konfigurationsmanagement zugeschnitten.

Durchführungs-Garantie: der Kurs wird auch bei nur einem Teilenmenden durchgeführt

Kurs buchen: https://www.gfu.net/seminare-schulungen-kurse/testmanagement_sk92/devops-softwareentwicklung-systemadministration_s2188.html

Jeder Teilenmende erhält eine gedruckte Ausgabe des Buches: Marco Schulz, CI mit Jenkins, Rheinwerk, 2021

Sollten Sie zu den angebotenen Terminen nicht können, beziehungsweise für Ihr Team einen individuellen Termin wünschen, um beispielsweise in einer geschlossenen Runde auf konkrete Problemstellungen eingehen zu können, besteht die Möglichkeit zusätzliche außerplanmäßige Termine zu vereinbaren. Nutzen Sie bitte hierzu mein Kontaktformular unter der Angabe welchen Kurs Sie wünschen, mit Terminvorschlägen und der zu erwartenden Teilnehmerzahl.

Weitere Termine:

  • 25.01 – 27.02.2023 (KW 04)
  • 26.04 – 28.04.2023 (KW 17)
  • 05.07 – 08.07.2023 (KW 27)
  • 25.10 – 27.10.2023 (KW 43)