Clients und Server-Stubs mittels Swagger Codegen erzeugen

Mit Swagger gibt es seit einigen Jahren eine Möglichkeit REST-API sinnvoll zu dokumentieren und zu generieren. Aus einer YAML-Datei, welche die Beschreibung der API enthält kann mit dem Swagger Code Generator (kurz Swagger Codegen) eine entsprechende Client-Bibliothek oder ein Server-Stub erzeugt werden. Eine solche minimale YAML-Datei könnte wie folgt aussehen:

swagger: '2.0'
info:
  description: "API"
  version: "2018.04"
  title: "API"
host: "api.example.com"
basePath: "/v1"
schemes: 
- "https"
paths:
  /tree:
    get:
      produces: 
      - "application/json"
      summary: Returns the document tree
      tags:
      - "Document tree"
      description: Lorem Ipsum dolor sit amet
      responses:
        200:
          description: OK

In dieser Datei wird eine Ressource mit dem Namen tree und für diese eine Get-Methode definiert. Um daraus nun die Client-Bibliotheken bzw. Server-Stubs zu generieren muss der Swagger Codegen über Git bezogen, anschließend kompiliert und paketiert werden:

https://github.com/swagger-api/swagger-codegen.git
cd swagger-codegen
mvn clean package

Zur Erzeugung eines PHP-Server-Stubs mit dem Slim-Framework kann der Swagger Codegen anschließend wie folgt genutzt werden:

java -jar modules/swagger-codegen-cli/target/swagger-codegen-cli.jar generate -i api.yaml   -l slim -o folder/slim

Eine Client-Bibliothek wird auf dem gleichen Weg erzeugt:

java -jar modules/swagger-codegen-cli/target/swagger-codegen-cli.jar generate -i api.yaml   -l javascript -o folder/javascript

In diesem Fall wird eine JavaScript-Client-Bibliothek erzeugt. Die verfügbaren Sprachen bzw. Frameworks für die Clients und Server-Stubs erzeugt werden können, können mit dem Befehl:

java -jar modules/swagger-codegen-cli/target/swagger-codegen-cli.jar langs

angezeigt werden. Die Ausgabe spezifiziert alle vorhandenen Generatoren:

Available languages: [ada, ada-server, akka-scala, android, apache2, apex, aspnetcore, bash, csharp, clojure, cwiki, cpprest, csharp-dotnet2, dart, elixir, elm, eiffel, erlang-client, erlang-server, finch, flash, python-flask, go, go-server, groovy, haskell-http-client, haskell, jmeter, jaxrs-cxf-client, jaxrs-cxf, java, inflector, jaxrs-cxf-cdi, jaxrs-spec, jaxrs, msf4j, java-pkmst, java-play-framework, jaxrs-resteasy-eap, jaxrs-resteasy, javascript, javascript-closure-angular, java-vertx, kotlin, lua, lumen, nancyfx, nodejs-server, objc, perl, php, powershell, pistache-server, python, qt5cpp, r, rails5, restbed, ruby, rust, rust-server, scala, scala-gatling, scala-lagom-server, scalatra, scalaz, php-silex, sinatra, slim, spring, dynamic-html, html2, html, swagger, swagger-yaml, swift4, swift3, swift, php-symfony, tizen, typescript-aurelia, typescript-angular, typescript-inversify, typescript-angularjs, typescript-fetch, typescript-jquery, typescript-node, undertow, ze-ph, kotlin-server]

Lizenziert ist der Swagger Codegen unter der Apache Licence in der Version 2 und somit freie Software.

Garbage Collection Log erstellen und auswerten

In regelmäßigen Abstand führen Java-Applikationen eine sogenannte Garbage Collection durch. Dabei werden Objekte welche nicht mehr benötigt werden entfernt und somit der Speicher der Anwendung bereinigt. Die Ausführung der Garbage Collection kann während der Ausführung der Applikation mitgeloggt werden:

java -Xloggc:garbage.log -jar application.jar

Der Parameter -Xloggc spezifiziert die Datei in welche das Log geschrieben wird. Mit Hilfe dieses Logs können Probleme der Applikationen analysiert werden. Ein Beispiel für ein solches Log könnte z.B. so aussehen:

Java HotSpot(TM) 64-Bit Server VM (25.144-b01) for bsd-amd64 JRE (1.8.0_144-b01), built on Jul 21 2017 22:07:42 by "java_re" with gcc 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2336.11.00)
Memory: 4k page, physical 8388608k(122952k free)

/proc/meminfo:

CommandLine flags: -XX:InitialHeapSize=134217728 -XX:MaxHeapSize=2147483648 -XX:+PrintGC -XX:+PrintGCTimeStamps -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseParallelGC 
4,347: [GC (Allocation Failure)  33280K->8385K(125952K), 0,0125825 secs]
4,475: [GC (Metadata GC Threshold)  12196K->8961K(125952K), 0,0061766 secs]
4,481: [Full GC (Metadata GC Threshold)  8961K->6026K(87552K), 0,0206784 secs]
16,232: [GC (Allocation Failure)  39306K->15981K(87552K), 0,0095999 secs]

Zur Auswertung kann, neben vielen anderen Tools, der Webdienst GCeasy, welcher sich selbst als Universal GC Log Analyzer bezeichnet, genutzt werden.

Die Analyse des Garbage Collection Logs

Mit Hilfe der Auswertung können eventuelle Probleme im Zusammenhang mit der Garbage Collection besser eingegrenzt und analysiert werden. Zu finden ist der Dienst unter gceasy.io.

Domänenspezifische Sprache für Tests von REST-Schnittstellen

Eine domänenspezifische Sprache, kurz DSL, ist eine auf ein bestimmtes Problemfeld abgestimmte Sprache. Mit dem freien REST Assured existiert eine solche Sprache für den effektiven Test von REST-Schnittstellen. Genutzt wird REST Assured hauptsächlich unter Java und Groovy. Eine einfache Überprüfung des Statuscodes einer API-Anfrage würde in REST Assured wie folgt aussehen:

given().get("api.example.com").then().assertThat().statusCode(200);

Daneben sind auch komplexe Tests wie die Auswertung von zurückgegebenen JSON-Strukturen und Daten, sowie die Verknüpfung unterschiedlicher Bedingungen ohne Probleme zu implementieren. Eine große Übersicht über die Möglichkeiten von REST Assured bietet der Usage-Guide des Projektes.

rest-assured.io

Die Projektseite von REST Assured ist unter rest-assured.io zu finden. Der unter der Apache Lizenz (Version 2.0) lizenzierte Quellcode kann auf GitHub gefunden werden.

Java-Projekte automatisch erzeugen

Es gibt praktische Software und dann gibt es manchmal Anwendungen bei denen man sich fragt was genau der Anwendungszweck ist. Eine dieser Anwendungen ist der Java Bullshifier. Die einzige Aufgabe des Java Bullshifier ist es, riesige Java-Projekte zu erzeugen.

Die Projekt-Webseite

Selbst im Vorstellungsartikel des Tools wird die Meinung vertreten, das es ein wenig esoterisch wirkt. Im Artikel wird allerdings ebenfalls die Motivation bzw. die Nutzung des Tools beschrieben:

It’s used in order to test some of our monitoring capabilities over ridiculously large code bases, with transactions that go thousands of calls deep, over thousands of classes, and end up with exceptions.

Erzeugt werden ein Projekt mit einer beliebigen Anzahl an Klassen und für eine Klasse sieht der generierte Quelltext exemplarisch wie folgt aus:

package generated.afz.qen.lrlj;

import helpers.Config;
import helpers.Context;
import java.util.*;
import java.util.logging.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;

public class ClsTvxlbccvg
{
    public static final int classId = 325;
    static final Logger logger = LoggerFactory.getLogger(ClsTvxlbccvg.class);

    public static void metWrkbglgpwrbj(Context context) throws Exception
    {
        int methodId = 0;
        Object[] root = new Object[8];
        Map<Object, Object> valUmbeeuzlkcg = new HashMap();
        Object[] mapValTaglolagfcm = new Object[10];
        String valLjtuhkvukba = "StrHwrvspzqwyp";

        mapValTaglolagfcm[0] = valLjtuhkvukba;
    
        for (int i = 1; i < 10; i++)
        {
            mapValTaglolagfcm[i] = Config.get().getRandom().nextInt(1000);
        }

        Set<Object> mapKeyGfqzkkkweud = new HashSet<Object>();
        long valZqatretqosu = 2690648861024756176L;

Der Quelltext des Java Bullshifier ist auf GitHub zu finden. Er ist unter der MIT-Lizenz lizenziert und damit freie Software.

Mit der java.time-API die UTC ermitteln

Seit Java 8 gibt es durch den JSR-310 eine neue API für Daten- und Zeitoperationen. Möchte man in dieser API die aktuelle Zeit ermitteln so würde dies so aussehen:

LocalDateTime now = LocalDateTime.now();

Dadurch erhält man die lokale Zeit des Rechners auf dem dieser Codeschnipsel ausgeführt wird. Damit ist das Problem auch schon beschrieben; man erhält nur die lokale Zeit. Wenn mehrere Systeme zusammen arbeiten soll, kann dies zu einem Problem führen. Natürlich könnte man ZonedDateTime nutzen:

ZonedDateTime now = ZonedDateTime.now();

Damit bleibt die Information über die verwendete Zeitzone erhalten. Benötigt man nun z.B. die UTC, also die koordinierte Weltzeit, so könnte man die Zeitdifferenz mittels:

now.getOffset()

ermitteln und diesen Wert für die Berechnung der UTC nutzen. Einfacher funktioniert es allerdings über den kleinen Umweg mit der Clock-Klasse:

LocalDateTime now = LocalDateTime.now(Clock.systemUTC());

Damit befindet sich in der Variable now, das aktuelle Datum und die aktuelle Uhrzeit als UTC.