JSON mit Schlüsselwörtern unter Java deserialisieren

Mittels GSON von Google, können JSONs unter Java einfach in Objekte deserialisiert werden. Allerdings können bestimmte JSON-Objekte zu Problemen führen. So zum Beispiel folgende JSON-Datei:

{
   "default":"ABC",
   "value":"DEF"
}

Das entsprechende Java-Objekt könnte in diesem Fall wie folgt aussehen:

class Data {

  public String default;
  public String value;
}

Damit wäre GSON in der Lage die entsprechenden Felder aus dem JSON, den Felder in der Klasse zuzuordnen. Allerdings kann obige Klasse nicht kompiliert werden. Hintergrund hierfür ist das Feld default. Unter Java ist dies ein Schlüsselwort und kann somit nicht als Feldname genutzt werden. Unter Sprachen wie C# könnte hier mit einer Verbatim-Zeichenkette gearbeitet werden:

public String @default;

Allerdings bietet Java diese Möglichkeit nicht an, sodass sich hier anders beholfen werden muss. Die Lösung ist die Annotation SerializedName. Diese gibt den Namen des Schlüssels im JSON an, welcher in das entsprechende Feld deserialisiert werden soll:

class Data {

  @SerializedName("default")
  public String defaultValue;
  public String value;
}

Damit kann GSON die Serialisierung wieder vornehmen und das obige JSON kann in eine entsprechende Java-Struktur abgebildet werden.

Klassenname für Logger unter Java automatisch ermitteln

Vor einiger Zeit schrieb ich einen Artikel darüber, wie der Klassenname für einen Logger ermittelt werden kann. Im Endergebnis sah die damalige Lösung, unter Nutzung der Simple Logging Facade for Java kurz SLF4J, wie folgt aus:

Logger log = LoggerFactory.getLogger(new Exception().fillInStackTrace().getStackTrace()[0].getClassName());

Damit wird der gesamte Stacktrace zusammengesammelt und entsprechend der Klassenname extrahiert. Das Problem an dieser Variante ist das der gesamte Stack dafür ausgewertet wird und für jede Nutzung eines Logs eine relativ unintuitive und lange Zeile von A nach B kopiert werden muss. Anders sieht es mit folgender Lösung aus:

package net.seeseekey.example;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Utility class to get logger
 */
public final class Logging {

    private Logging() {
    }

    public static Logger getLogger() {

        StackWalker.StackFrame frame = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE)
                .walk(stream -> stream.skip(1)
                        .findFirst()
                        .orElse(null));

        if (frame == null) {
            return LoggerFactory.getLogger("Common");
        }

        return LoggerFactory.getLogger(frame.getClassName());
    }
}

Bei dieser Utility-Klasse wird der entsprechende Klassenname dynamisch über einen StackWalker ermittelt. Zurückgegeben wird hierbei der Klassenname des Aufrufers. Konnte kein Klassenname ermittelt werden, so wird stattdessen ein Logger mit dem Namen Common zurückgegeben. Damit kann der eigentliche Logger nun wie folgt angelegt werden:

Logger log = Logging.getLogger();

Der StackWalker ist ab Java 9 verfügbar und kann somit in neueren Projekten problemlos genutzt werden. Im Gegensatz zu den bisherigen Methoden Teile des Stacktrace zu erhalten, ist der StackWalker aus Performancesicht zu bevorzugen. Definiert wurde diese API in der JEP 259.

Probleme beim Deployen zu Maven Central

Im Rahmen einiger Wartungsarbeiten wollte ich eine neue Version einer Java-Bibliothek zu Maven Central deployen. Stattdessen wurde ich von der Meldung:

Execution injected-nexus-deploy of goal org.sonatype.plugins:nexus-staging-maven-plugin:1.6.7:deploy failed: An API incompatibility was encountered while executing org.sonatype.plugins:nexus-staging-maven-plugin:1.6.7:deploy: java.lang.ExceptionInInitializerError: null

überrascht. Am dahinterliegenden Problem wird bereits gearbeitet. Um das Deployment trotzdem durchführen zu können, eignet sich folgender Workaround:

export MAVEN_OPTS="--add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/java.lang.reflect=ALL-UNNAMED --add-opens=java.base/java.text=ALL-UNNAMED --add-opens=java.desktop/java.awt.font=ALL-UNNAMED"
mvn clean deploy

Anschließend wird das entsprechende Deployment durchgeführt, was je nach Auslastung einige Minuten dauern kann.

Nyan-Katze in IntelliJ IDEA

Eine Entwicklungsumgebung ist ein trister Ort. Aber manchmal hilft schon etwas Farbe, um aus einem tristen Ort etwas Schönes zu machen. So kann die IDE IntelliJ IDEA mit unterschiedlichsten Plugins erweitert und verändert werden.

Der Fortschrittsbalken in Aktion

Eines dieser Plugins ist die Nyan Progress Bar. Das Plugin ersetzt den Fortschrittsbalken durch einen Regenbogen auf dem die Nyan-Katze sich bewegt. Installiert werden kann das Plugin über den in IntelliJ IDEA integrierten Plugin-Manager. Der Quelltext des Plugins ist auf GitHub zu finden. Es ist unter der Zero-Clause BSD-Lizenz lizenziert und damit freie Software.