JSON - JAX https://jax.de/tag/json/ Java, Architecture & Software Innovation Fri, 18 Oct 2024 12:52:55 +0000 de-DE hourly 1 https://wordpress.org/?v=6.5.2 Techniken asynchroner Web-APIs https://jax.de/blog/techniken-asynchroner-web-apis/ Fri, 06 Oct 2023 11:09:56 +0000 https://jax.de/?p=89033 Neulich musste ein Kunde ein HTTP-basiertes Web-API für seine Daten bereitstellen. Das Problem: Die angebotenen Daten waren nicht direkt vorhanden, sondern erst nach einiger Zeit. Das API musste also eine Antwort nachliefern. Aber wie kann diese Art eines API umgesetzt werden? Ohne die Alternativen zu kennen, ist der Kunde schlecht beraten. Grund genug, sich verschiedene Techniken anzuschauen und zwischen deren Trade-offs abzuwägen.

The post Techniken asynchroner Web-APIs appeared first on JAX.

]]>
Klassische HTTP-basierte-APIs sind häufig synchron. Auf eine Anfrage folgt prompt eine Antwort. Nicht immer sind Antworten, wie im Falle unseres Kunden, jedoch sofort verfügbar, z. B., weil noch externe Systeme angefragt werden müssen. Das API ist also asynchron. Doch wie kann ein HTTP API asynchron abgebildet werden, wenn das HTTP-Protokoll doch konzeptionell synchron ist?

Wenn die Daten schon da sind

Normalerweise passieren Daten, damit sie von einem System in ein anderes gelangen, immer eine Schnittstelle (API). Klassischerweise ist diese HTTP-basiert, wie auch in diesem Fall. Das bedeutet, dass, um Daten anzufragen, ein HTTP Request gesendet wird, wie in Abbildung 1 gezeigt.

Abb 1: Synchrones API

Das Web-API eines Systems übersetzt diese Anfrage z. B. in eine SQL-Abfrage, transformiert das Ergebnis in ein Serialisierungsformat, wie beispielsweise JSON – manchmal sogar HTML oder XML –, und sendet dem Anfragenden das Ergebnis. Diese Art von Prozess hat allerdings eine Implikation: Der gesamte Prozess blockiert, weil er synchron ist. Ist die konsumierende Applikation des API beispielsweise ein Browser, sieht der Nutzer für die gesamte Laufzeit eine Ladeanzeige.

Stay tuned

Regelmäßig News zur Konferenz und der Java-Community erhalten

 

Erst wenn das API die Antwort geliefert hat, wird in der Applikation weiterverfahren. Sowohl Applikation als auch API müssen eine Verbindung offenhalten, bis die Daten übertragen wurden. Der Zustand des Prozesses, erkennbar durch die grünen Balken in der Spalte der Applikation, wird damit (kurzzeitig) über die TCP-Verbindung abgebildet. Solch eine Kommunikation des API ist glücklicherweise relativ trivial und kurzlebig. Diese Art der Kommunikation ist konzeptionell synchron und für die meisten Web-APIs ausreichend.

Die Daten warten noch

Komplexer ist es, wenn der API-Server nicht mit einer eigenen Datenhaltung kommuniziert, die Daten direkt bereithält, sondern ein komplexerer Prozess existiert, der eine Antwort erst viel später – asynchron – liefert. Im folgenden Beispiel also das Anlegen einer Bestellung. In diesem Falle ist es notwendig, für den API-Server ein API bereitzustellen, das diese Asynchronität unterstützt. Die wohl simpelste Möglichkeit, Daten eines asynchronen API bereitzustellen, ist die über die Methode Polling (Abb. 2).

Abb. 2: Polling: das wiederholte Anfragen des Zustands

Beim Polling führt eine Applikation im Beispiel ein Erstellen von Daten aus und erhält dabei den aktuellen Zustand, während auf einem asynchronen externen System (z. B. einer Message Queue) eine Anfrage gestellt wird. Asynchronität bedeutet in der Implementierung immer, dass es einen Zwischenzustand („Wartend“) gibt, der ein nicht vorhandenes Ergebnis abbilden kann. Nach dem Erstellen erhält der Konsument in der Regel deshalb einen Datensatz, der eben diesen Zustand enthält. Ob das Ergebnis im Zustand „Wartend“ ausreichend ist, kann nur der Konsument des API selbst entscheiden. In den meisten Fällen ist das nicht der Fall. Der Zustand der Kommunikation bleibt deshalb weitgehend dem Konsumenten des API überlassen, denn dieser muss entscheiden, ob alle Daten vorhanden sind oder ob weitere Aktualisierungsschritte eingeleitet werden müssen.

Genau für diese weiteren Aktualisierungsschritte muss der API-Server einen zweiten Endpunkt implementieren, der den aktuellen Stand einer Bestellung (Order) für den aktuellen Zustand abfragbar macht. Der Konsument muss also selbst einen Mechanismus implementieren, innerhalb dessen er wiederholt den API-Server anfragt, je nachdem, ob die Daten aktuell genug sind. Im Beispiel wird die Bestellung mit der ID 1 wiederholt angefragt.

DIE KUNST DER SOTWARE-ARCHITEKTUR

Architecture & Design-Track entdecken

 

Die Schwierigkeit bei einem solchen Modell ist das Finden eines geeigneten Intervalls. Es ergibt wenig Sinn, bei einem Prozess, der Tage in Anspruch nimmt, im Minutentakt eine Aktualisierung zu erfragen. Ein API-Server muss deshalb bei tendenziell vielen Clients viele „leere Nachrichten“ verarbeiten. Der Vorteil liegt aber klar auf der Hand: Es ist Aufgabe des Clients, die aktuellen Daten zu erhalten. Der API-Server ist im Kommunikationsprozess relativ zustandslos.

Verbindungen reduzieren durch Long Polling

Eine Alternative für das regelmäßige Polling mit Intervall ist das Long Polling (Abb. 3). Dabei wird nach einer Anfrage die technische Verbindung so lange offengehalten, bis das Ergebnis letztlich eintritt, ähnlich wie es von TCP-Verbindungen bekannt ist.

Abb. 3: Long Polling: Verbindungen reduzieren

Diese Technik impliziert, dass der API-Server sehr lange eine HTTP-Verbindung offenhalten muss. Das kostet Speicher und muss von der Infrastruktur und deren Konfiguration unterstützt werden. Sowohl der Konsument als auch der API-Server, der die Daten bereitstellt, müssen eine Verbindung offenhalten bzw. regelmäßig erneuern wie beim Polling. Auch bei dieser Technik muss der Konsument des API einen Zustand vorhalten, der ein erneutes Abfragen des API anspricht. Es wird also ein technisches Problem gelöst, nicht aber der konzeptionelle Umstand der Datenverwaltung.

Stay tuned

Regelmäßig News zur Konferenz und der Java-Community erhalten

 

Verbindungen minimieren durch Webhooks

Da es sich um einen Anwendungsfall von zwei vertrauenswürdigen Applikationen – Backend genannt – handelte, ist noch eine weitere Art von API möglich: Webhooks (Abb. 4).

Die Idee von Webhooks ist es, einen Kommunikations-Overhead der zuvor genannten Techniken zu mitigieren und stattdessen den Umstand auszunutzen, dass sowohl der Konsument als auch der Anbieter des API selbst eine Schnittstelle anbieten kann.

Abb. 4: Webhooks

Der Konsument des API bietet bei diesem Ansatz selbst ein beliebiges Callback API an – im Beispiel erreichbar unter dem URL /orders-received. Genau diesen URL teilt der Konsument beim Erstellen der Anfrage mit. Im Bild also foo.bar/orders-received. Der API-Server selbst speichert diesen in einer beliebigen Datenhaltung ab und stellt die Anfrage an das asynchrone System. In diesem Falle die Message Queue.

Erhält der API-Server eine Antwort auf die initial gestellte Anfrage durch die Message-Queue, kann dieser durch die zuvor vorgehaltene Abbildung von erstelltem Objekt und Callback-URL das entsprechende API des Konsumenten aufrufen. Eins ist damit klar erkennbar: Im Gegensatz zum Polling ist es bei Webhooks die Aufgabe des Servers, die Daten an den Konsumenten zu liefern. Die Zuständigkeiten haben sich damit verändert.

Durch eine Kommunikation über Webhooks werden die Nachteile des Polling vermieden. Diese Technik ist aber nicht überall einsetzbar – schließlich kann nicht jeder Konsument eines API, z. B. Browser, auch selbst ein API anbieten. Diese Technik ist damit nur eingeschränkt nutzbar. Ist der Konsument ein Browser, ist ein solches API kaum abbildbar, da es keine mir bekannte Möglichkeit gibt, dass der Browser als zuverlässiger Server fungiert.

Natürlich hat diese Art der Kommunikation auch noch weitere Nachteile. Beispielsweise ist der Konsument gezwungen, ein Callback API anzubieten und wird damit vom Konsumenten eines API zum Anbieter eines API.

 

Ist der Konsument des API unzuverlässig, z. B., weil die Applikation regelmäßig abstürzt, hat der API-Server nun außerdem die Aufgabe, gewisse Fehlertoleranzen zu implementieren. Das kann zum Beispiel durch Retry-Mechanismen geschehen – Aufgaben, die beim Polling-Ansatz nicht existieren würden, da der Client dort reiner Konsument ist und es sich um zustandslose Beziehung handelt.

Fazit

Die meisten HTTP-basierten Schnittstellen sind Request-Response-basiert und damit relativ trivial umzusetzen. Auf eine Anfrage folgt eine Antwort. Schwieriger wird es, wenn Asynchronität ins Spiel kommt. Für die Asynchronität muss ein Mechanismus her. In verteilten Systemen wird häufig das erneute Anfragen von Daten, genannt Polling, angewendet, um Daten regelmäßig zu untersuchen. Durch das Long Polling kann diese Technik dahingehend verändert werden, dass ein ständiges Auf- und Abbauen von Verbindungen verhindern.

Bei einer Backend-zu-Backend-Kommunikation wird häufig auf Webhooks gesetzt. Webhooks machen einen asynchronen Prozess Event- statt aktualisierungsgetrieben. Dadurch werden unnötige Kommunikationswege vermieden. Das ist nicht komplett kostenlos: Der API-Konsument ist nun in der Pflicht, selbst ein API bereitzustellen, und der API-Anbieter muss den Zustand der Kommunikation – also „wer ist an welchen Daten interessiert?“ – übernehmen.

Eins ist allerdings klar: Bei beiden Ansätzen muss auch die implementierende Seite des Clients Hand anlegen, sei es in Form einer Aktualisierungsschleife oder in Form eines eigenen HTTP API.

The post Techniken asynchroner Web-APIs appeared first on JAX.

]]>
Ein Liebesbrief an die Java-Community https://jax.de/blog/ein-liebesbrief-an-die-java-community/ Fri, 01 Sep 2023 06:14:04 +0000 https://jax.de/?p=88940 Ich möchte diesen Artikel nutzen, um vielen Menschen und Unternehmen zu danken. Ein solches Projekt mit meinem Sohn ist nur möglich, weil sie fantastische Bibliotheken und Werkzeuge geschaffen haben, mit denen wir Anwendungen schnell entwickeln können.

The post Ein Liebesbrief an die Java-Community appeared first on JAX.

]]>
In meinem vorherigen Artikel [1] habe ich gezeigt, wie ich Java Enums verwende, um die Kategorien für Videos auf der Website https://4drums.media [2] zu definieren. Diese Website ist ein Lieblingsprojekt, das ich zusammen mit meinem dreizehnjährigen Sohn entwickelt habe.

Ich werde hier nicht das gesamte Projekt mit Ihnen teilen und Ihnen den kompletten Code zeigen. Nein, ich möchte die Gelegenheit vielmehr nutzen, um allen zu danken, die es uns ermöglicht haben, diese Website zu erstellen!

Abb. 1: Die verfügbaren Video- und Tutorialkategorien auf der Website 4drums.media

Stay tuned

Regelmäßig News zur Konferenz und der Java-Community erhalten

 

Über 4drums.media

Wie viele Jugendliche heutzutage möchte auch mein Sohn „im Internet berühmt“ werden – er spielt Schlagzeug, seitdem er ein kleiner Junge ist. Um seine Ambitionen zu unterstützen, haben wir gemeinsam eine Website erstellt, auf der er Schlagzeugvideos veröffentlichen und eine Community aufbauen kann, die sich für das Schlagzeugspielen interessiert. Da er kein Budget hat, ist das Hosten und Bearbeiten von Videos keine Option. Glücklicherweise bieten YouTube und Vimeo APIs an, um mit ihren Diensten zu interagieren. In Kombination mit meinen Erfahrungen mit Spring Boot, Vaadin usw. konnten wir schnell loslegen und hatten bald die erste Version, die jetzt verfügbar ist. Werfen wir einen Blick auf die von uns verwendeten Tools, die Sie für Ihr nächstes persönliches oder berufliches Projekt inspirieren könnten.

IntelliJ IDEA

Visual Studio Code, Eclipse, NetBeans – alles großartige und kostenlose IDEs zur Erstellung von Java-Code. Aber die am häufigsten verwendete IDE ist seit vielen Jahren IntelliJ IDEA [3]. Ich benutze die (kostenpflichtige) Ultimate Edition, aber die kostenlose Community Edition ist genauso gut. Und ja, mein Sohn benutzt diese Version auf seinem Schul-PC! Am Code selbst hat er nicht mitgewirkt, aber ich konnte ihn einfach die neueste Version ziehen lassen, ein paar Farben und Symbole hinzufügen, lokal testen und sie dann wieder in das Repository einspeisen. Und dank des automatisierten Builds (siehe GitHub weiter unten) kann er die Änderungen innerhalb weniger Minuten live sehen. Ist es nicht großartig, dass jeder, vom Anfänger bis zum erfahrenen Benutzer, ein solch fantastisches Tool frei nutzen kann? Vielen Dank, JetBrains!

Spring Boot und Bibliotheken

Ich liebe Quarkus, Micronaut und andere, weil sie viel Evolution in die Java-Welt gebracht haben. Da ich jedoch bereits viel Erfahrung mit Spring Boot [4] hatte, habe ich diesen Weg weiterverfolgt. Aber es ist nicht nur Spring selbst, das dieses System zu einem fantastischen Framework macht. Es ist die Kombination mit Flyway zur Erweiterung der Datenbankstruktur, H2 für lokale Tests, Jsoup zur Validierung von Texteingaben, JUnit für Tests usw. Ich bin also nicht nur Spring dankbar, sondern auch den vielen Unternehmen und Entwicklern, die großartige Java-Bibliotheken und -Tools entwickeln!

YouTube und Vimeo

Einen Videodienst selbst zu hosten, würde den Rahmen eines Vater-Sohn-Projekts bei Weitem sprengen. Aber zum Glück müssen wir das nicht tun, denn viele Videodienste erlauben eine vollständige Integration. So können sie auf einfache Weise mehr Zuschauer anziehen, da ihre Videos in andere Websites integriert werden. Der Player unterliegt jedoch vollständig der Kontrolle des Anbieters, sodass jede Ansicht eines Videos (und der Werbung …) eine zusätzliche Ansicht für seine jeweilige Plattform darstellt.

Mit dem WebClient von Spring ist es mühelos möglich, die Beschreibung, den Kanal, das Vorschaubild und weitere Informationen z. B. von jedem YouTube-Video abzurufen. In Kombination mit Datensätzen, die der YouTube-API-Antwort-JSON [5] entsprechen, und der FasterXML-Bibliothek von Jackson ist nur minimaler Code erforderlich, um Daten anzufordern und das Ergebnis zu parsen (Listing 1).

public Optional<YouTubeApiResponse> getYouTubeVideoApi(String id) {
  String url = "https://www.googleapis.com/youtube/v3/videos"
  + "?id=" + id + 
  + "&part=snippet%2CcontentDetails%2Cstatistics"
  + "&key=" + apiKeyYouTube;
  YouTubeApiResponse video = webClient.get()
    .uri(URI.create(url))
    .retrieve()
    .bodyToMono(YouTubeApiResponse.class)
    .block();
  if (video == null) {
    logger.error("Could not get info from YouTube for {}", id);
    return Optional.empty();
  }
  logger.info("Video info from YouTube: {}", video.title());
  return Optional.of(video);
}

@JsonIgnoreProperties(ignoreUnknown = true)
@JsonInclude(JsonInclude.Include.NON_NULL)
public record YouTubeApiResponse(
  String kind,
  String etag,
  List<Item> items) {}

@JsonIgnoreProperties(ignoreUnknown = true)
@JsonInclude(JsonInclude.Include.NON_NULL)
public record Item(
  String kind,
  String etag,
  String id,
  Snippet snippet,
  ContentDetails contentDetails,
  Statistics statistics
) {
}

Vimeo bietet die gleiche Art von API [6], daher haben wir beide Dienste integriert. Mit dem Aufstieg des Fediverse werden Alternativen wie PeerTube [7] an Bedeutung gewinnen, und wir werden definitiv versuchen, die unterstützten Videoplattformen später zu erweitern.

SIE LIEBEN JAVA?

Den Core-Java-Track entdecken

 

Vaadin

Ich habe JavaFX schon oft für grafische Benutzeroberflächen auf dem Desktop verwendet. Mit Vaadin habe ich ein ähnlich leistungsfähiges und Java-basiertes Framework für die Websiteentwicklung gefunden. Mit reinem Java-Code können Sie sowohl das Backend als auch das Frontend innerhalb eines Maven-Projekts erstellen, das einfach zu paketieren und zu verteilen ist. Auf start.vaadin.com [8] können Sie die verschiedenen Seiten konfigurieren, die Sie benötigen (Abb. 2), das Theme gestalten (Abb. 3) und die Java- und Vaadin-Version auswählen, die Sie verwenden möchten. Wenn Sie fertig sind, können Sie ein vollständig vorbereitetes Maven-Projekt auf Basis von Spring Boot mit einem Mausklick herunterladen, entpacken und in der IDE öffnen und ausführen, um es weiter zu bearbeiten.

Abb. 2: Sie können die verschiedenen Seiten konfigurieren …

Abb. 3: … und das Theme gestalten

Jede Komponente ist auf der Vaadin-Website [9] sehr gut dokumentiert und mit viel Beispielcode versehen. Das Hinzufügen einer solchen Komponente zu den HTML-Seiten und das Verknüpfen mit einer Backend-Methode ist sehr einfach, wie Sie im Beispielcode für den Like-Button in Listing 2 sehen.

var like = new Button();
like.setIcon(VaadinIcon.THUMBS_UP_O.create());
like.setText(String.valueOf(numberOfLikes));
like.addClickListener(e -> {
  videoService.addLike(video, user);
});
add(like);

Abb. 4: Der Output von Listing 2

Vaadin bietet eine lizenzierte Version mit zusätzlichen erweiterten Komponenten (Charts, GridPro …) und Support. Dennoch bietet die freie und quelloffene Version selbst für viele Geschäftsfälle alle Tools, um eine vollständige Webanwendung zu erstellen. Ich habe sie in meinen früheren Jobs für Back-Office-Anwendungen verwendet, und die Entwicklungsgeschwindigkeit, die sich aus einer einzigen Codebasis für APIs und UI ergibt, ist enorm!

 

PostgreSQL

Gibt es heute noch Websites, die keine Datenbank verwenden? Mein Weg zur Datenbank begann vor vielen Jahren mit Microsoft Access. Obwohl es nicht für die Verwendung im Web gedacht war, konnte ich viele dynamische Websites mit einer Access-Datenbank als Kern erstellen. Später habe ich SQL Server, MySQL, NoSQL-Datenbanken und andere verwendet. Aber ich denke, wir können festhalten, dass PostgreSQL [10] den größten Teil der Welt der Onlinedatenbanken erobert hat. Ich liebe Tools, die einfach da sind, um die man sich nicht kümmern muss und die das tun, was sie tun sollen. Genau das hat PostgreSQL für mich seit vielen Jahren getan. Und auch hier ist die Kombination mit Spring Boot erstaunlich einfach und unkompliziert.

GitHub-Repository und Aktionen

Da ich nun schon seit einiger Zeit in dieser Branche tätig bin, habe ich viele Entwicklungen in der Art und Weise gesehen, wie Quelldateien verwaltet und gemeinsam genutzt werden. Von einem normalen Dateiserver mit ständigen Konflikten, über CVS, SVN bis hin zu Git. Im Foojay-Podcast „The Future of Source Control and CI/CD“ [11] sind wir zu dem Schluss gekommen, dass das aktuelle Git wahrscheinlich kein Endpunkt ist und wir weitere Entwicklungen sehen werden. Ist es nicht seltsam, dass nur die Softwareindustrie einen solchen Workflow angenommen hat? Warum verwendet z. B. der Gesetzgeber nicht denselben Ansatz, während die Erweiterung und Verbesserung von Gesetzen eigentlich sehr ähnlich ist und auf einem System von „Patches“ basiert? Könnte es sein, dass Trunks, Merge-Konflikte und zu viele mögliche Befehle Git zu kompliziert machen? Und dass nur Softwareentwickler in der Lage zu sein scheinen, mit diesen Herausforderungen fertigzuwerden?

Die Beantwortung dieser Fragen würde den Rahmen dieses Artikels sprengen, aber ich bin auf jeden Fall sehr dankbar für das, was GitLab, GitHub und Co. als kostenlosen Service für Open-Source- und Pet-Projekte anbieten. Ein zuverlässiges Versionskontrollsystem zu haben, ohne sich um Serverkosten, Back-ups, Upgrades usw. kümmern zu müssen, ist die erste Hürde, die diese Anbieter nehmen. Aber für mich ist der wichtigste Grund, sie zu lieben, die CI/CD, die sie bieten. Dank GitHub Actions führt jeder Commit in das Repository dazu, dass eine neue Websiteversion innerhalb von Minuten bereitgestellt wird, und zwar vollständig automatisiert, dank einer einzigen .yml-Datei. Ja, wir sind uns alle einig, dass YAML ätzend ist und das Erreichen einer funktionierenden Aktionsdatei nervt, aber wenn man eine funktionierende Lösung hat und sich nicht mehr um den Build- und Deployment-Prozess kümmern muss, ist das ein echter Meilenstein in jedem Projekt!

Stay tuned

Regelmäßig News zur Konferenz und der Java-Community erhalten

 

Uberspace

Bis jetzt habe ich die meisten der Tools aufgelistet, die ich für die 4drums.media-Website verwendet habe und die alle kostenlos erhältlich sind! Jetzt bleibt nur noch ein letzter Schritt für jede Website: ein Onlinezuhause finden. Die Möglichkeiten sind endlos, von Shared Hosting über VPS bis hin zu kompletten Netzwerkumgebungen bei AWS, Azure oder jedem anderen Anbieter. Von nicht so günstig bis sehr teuer …

Da unser Budget für dieses Projekt sehr begrenzt ist (eigentlich nichtexistent), habe ich in Deutschland eine schöne Lösung bei uberspace.de [12] gefunden. Mit einem Pay-as-you-want-Modell ab 5 Euro/Monat bekommt man einen VPS, den man nach Bedarf konfigurieren kann. In unserem Fall bedeutete das, die richtige Java-Version und PostgreSQL zu installieren. Mit einer sehr detaillierten Dokumentation [13] war jeder Schritt in diesem Prozess eine schnelle und angenehme Erfahrung. Und wenn man nicht weiterkommt, antwortet der Support schnell und hilft einem oder verweist auf die richtige Dokumentation.

Das Hosting der Website (und des Domänennamens) ist also der einzige Teil dieses Projekts, bei dem „Herr Visa“ uns helfen musste, aber der Betrag ist trotzdem minimal.

Fazit

Java ist nicht nur eine Sprache und eine Laufzeitumgebung. Es ist auch eine große Gemeinschaft von Menschen und Unternehmen, die erstaunliche Dinge entwickelt, die in den meisten Fällen kostenlos genutzt werden können. Teil dieser Gemeinschaft zu sein, ist eine tägliche Freude, und ich bin wirklich dankbar, dass all das verfügbar ist! Deshalb sage ich allen, die einen Beitrag leisten und all dies möglich machen: Danke! Aus tiefstem Herzen!


Links & Literatur

[1] Delporte, Frank: „Verborgene Schönheiten“; in Java Magazin 9.2023

[2] https://4drums.media

[3] https://www.jetbrains.com/idea/

[4] https://start.spring.io

[5] https://developers.google.com/youtube/v3/

[6] https://developer.vimeo.com

[7] https://joinpeertube.org

[8] https://start.vaadin.com

[9] https://vaadin.com/docs/latest/components

[10] https://www.postgresql.org

[11] https://foojay.io/today/foojay-podcast-26/

[12] https://uberspace.de

[13] https://manual.uberspace.de

[14] https://webtechie.be/books

The post Ein Liebesbrief an die Java-Community appeared first on JAX.

]]>
Zehn Must-have-Java-Bibliotheken https://jax.de/blog/zehn-must-have-java-bibliotheken/ Tue, 09 Mar 2021 10:25:27 +0000 https://jax.de/?p=82839 Java-Entwickler können ein Lied davon singen: heruntergeladene Bibliotheken, die nicht funktionieren oder das Programm zum Absturz bringen. Andererseits kommen Entwickler um gewisse Java-Bibliotheken nicht herum, wenn sie Wert auf Komfort legen.

The post Zehn Must-have-Java-Bibliotheken appeared first on JAX.

]]>
Es kann nicht schaden, über den Tellerrand zu blicken, um einen eleganteren Code zu schreiben. Denn reiner Java-Code kann verglichen mit Java-Bibliotheken zum Teil umständlich sein. Aus diesem Grund dreht sich hier alles um zehn Java-Bibliotheken, die das Coden erleichtern.

Apache Commons

Apache Commons ist eine Sammlung mehrerer Komponenten, die von der Apache Software Foundation entwickelt werden. Zu den bekanntesten Komponenten zählt sicherlich Apache Commons Lang, die das Basispaket Java.lang erweitert. Darin befinden sich Klassen, um die Zeit und das Datum zu formatieren (apache.lang.time). Eine weitere beliebte Klasse nennt sich StringEscapeUtils. Damit können Strings mit Escape-Zeichen versehen werden. Die Klasse StringUtils stellt hingegen mehrere Methoden zur Bearbeitung von Strings zur Verfügung.

Einen Haufen Zeit erspart die Apache-Commons-Configuration-Komponente. Damit lassen sich im Nu Konfigurationsdateien erstellen und mit Schlüssel-Wert-Paaren versehen. Auch das Parsen der Konfigurationsdateien lässt sich leicht bewerkstelligen.

Verschaffen Sie sich den Zugang zur Java-Welt mit unserem kostenlosen Newsletter!

Lohnenswert ist zudem die Apache-Commons-Crypto-Bibliothek, mit der sich mit wenig Aufwand und Code Variablen ver- oder entschlüsseln lassen. Eine weitere empfehlenswerte Komponente ist Apache Commons Numbers. Sie beinhaltet mehrere Klassen, um Zahlen gemäß der Zahlenart zu formatieren. So ermöglicht die Klasse Complex das Erstellen von komplexen Zahlen, während die Klasse Fraction das Rechnen mit Brüchen erlaubt.

CalendarFX

Wer einen Terminplaner für eine Arztpraxis oder ein Ticketsystem implementieren möchte, der wird sich sicherlich Gedanken um die Ausgabe von Kalendern und um das Festlegen eines Termins machen. Hierbei kann das Framework CalendarFX, das sich in eine JavaFX-Anwendung einbinden lässt, nützlich sein (Abb. 1). Die CalendarFX-Bibliothek wird zurzeit in der Version 8 angeboten.

 



Abb. 1: Das CalendarFX Framework ermöglicht dem Anwender eine interaktive Sitzung

 

Google Guava

Ähnlich wie Apache Commons hat sich Google das Ziel gesetzt, die Effizienz bei der Produktion zu steigern. Mit Google Guava lässt sich der Code reduzieren sowie die Lesbarkeit und die Geschwindigkeit beim Entwickeln steigern. Die Guava-Bibliotheken verfügen über Stringverarbeitung, Collections, Graphen, Hashcodes, Exception Handling, Multithreading sowie weitere Bibliotheken. Aktuell ist Google Guava in der Version 30.0 verfügbar.

 

Apache Log4j 2

Zu den fortgeschrittenen Logging-Bibliotheken zählt Log4j 2. Deren Leistung kann sich sehen lassen. Denn je mehr Threads der Computer hat, auf dem die Anwendung läuft, desto mehr kann geloggt werden. Log4j 2 gibt es derzeit in der Version 2.14.0. Listing 1 zeigt, wie Log4j 2 eine Klasse loggt. Darüber hinaus verfügt Log4j 2 über eine Debug-Funktion.

 
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class Sailboat {
  private static final Logger logger = LogManager.getLogger(Sailboat.class);
    public void move () {
    logger.info("sailing");
   }
}

 

JFXtras

Bei JFXtras handelt es sich um eine Bibliothek für die JavaFX-Anwendung [5]. Diese Bibliothek stellt unter anderem Steuerelemente wie Accordion sowie diverse Datum- und Zeit-Picker zur Verfügung. Daneben gibt es Anzeigenelemente, die für ein Dashboard nützlich sein können. In Listing 2 wird eine JavaFX-Anwendung erstellt, die die Klasse MainView startet.

 
import javafx.application.Application;
import javafx.stage.*;

public class App extends Application
{
  public static void main (String[] args)
  {
     launch(args);
  }

    public void start(Stage primaryStage) {
       MainView mainView = new MainView();
       mainView.show(primaryStage);   
  }
}

 

Das Accordion (Abb. 2) wird in der Klasse MainView wie ein anderes JavaFX-Element vom Typ Node erzeugt und anschließend im VBox-Container gespeichert (Listing 3).

 
import javafx.stage.*;
import javafx.scene.*;
import javafx.scene.layout.*;
import javafx.scene.control.*;
import jfxtras.scene.control.AccordionPane;

public class MainView {
  private AccordionPane accordionPane;
  private VBox pane;
  public MainView() {
    setRootNode();
    three();
    createWindow();
 }
  public void createWindow() {
    this.pane = new VBox(10,this.accordionPane );
}
  public void setRootNode() {
    this.accordionPane = new AccordionPane();
    this.accordionPane.setPrefSize(800.0, 600.0);
  }

public void three() {
  this.accordionPane.addTab("test1", new Label("test 1"));
  this.accordionPane.addTab("test2", new Label("test 2"));
  this.accordionPane.addTab("test3", new Label("test 3"));
}
public void show(Stage stage) {
  Scene scene = new Scene(this.pane);
  stage.setTitle("jfxtras");
  stage.setScene(scene);
  stage.setResizable(true);
  stage.setMaximized(true);
  stage.initStyle(StageStyle.TRANSPARENT);
    stage.show();
 }
}

 



Abb. 2: Ohne ein CSS-Stylesheet sieht das Accordion ziemlich langweilig aus

 

BootstrapFX

Bootstrap gibt es nicht nur für Webseiten, sondern auch für JavaFX-Anwendungen. So beinhaltet BootstrapFX 0.2.4 jede Menge vordefinierte CSS-Klassen für die einzelnen JavaFX-Elemente. BootstrapFX muss lediglich in die JavaFX-Anwendung eingebunden werden. Anschließend lassen sich die JavaFX-Elemente durch Setzen von vordefinierten CSS-Klassen stylen. Listing 4 zeigt die Klasse MainView, die so ähnlich aufgebaut ist wie in Listing 3, nur dass hier der VBox-Container einen Button beherbergt (Abb. 3).

 

 
import javafx.stage.*;
import javafx.scene.*;
import javafx.scene.layout.*;
import javafx.scene.control.*;
import org.kordamp.bootstrapfx.scene.layout.Panel;

public class MainView {
  private Button button;
  private VBox pane;
  public MainView() {
    createButton();
    createWindow();
}
public void createWindow() {
  this.pane = new VBox(10,this.button );
}
public void createButton() {
  this.button = new Button("Click me!");
  this.button.getStyleClass().setAll("btn","btn-danger");
}
public void show(Stage stage) {
  Scene scene = new Scene(this.pane);
  scene.getStylesheets().add("bootstrapfx.css");
    stage.setTitle("Bootstrap");
    stage.setScene(scene);
    stage.setResizable(true);
    stage.setMaximized(true);
    stage.initStyle(StageStyle.TRANSPARENT);
    stage.setWidth(900);
    stage.setHeight(600);
    stage.show();
  }
}

 



Abb. 3: Das Aussehen des Buttons wird von Bootstrap festgelegt

 

Bouncy Castle

Bouncy Castle ist eine kostenlose Crypto-Bibliothek, mit der sich Text ver- und entschlüsseln lässt. Es verfügt über zahlreiche Klassen und Schnittstellen, die in der Javadoc-Dokumentation der Quelldatei erläutert werden. Eine Einführung in Bouncy Castle befindet sich in der Quelldatei unter bctls-jdk15on-167/docs/specifications.html. Seit November dieses Jahres ist Bouncy Castle in der Version 1.67 verfügbar.

Listing 5 zeigt, wie Text mit Bouncy Castle verschlüsselt wird. In diesem Beispiel entspricht die Länge der Variable KeyString der Länge des zu verschlüsselnden Texts, da es sonst zu einem Laufzeitfehler kommen würde.

 

 
import org.bouncycastle.crypto.*;
import org.bouncycastle.crypto.engines.*;
import org.bouncycastle.crypto.modes.*;
import org.bouncycastle.crypto.params.*;

public class CryptoTest {
  private static final String keyString = "keyfrase";
  private static final String inputString = "password";

  public BlockCipher createEngine() {
    BlockCipher engine = new DESEngine();
    return engine;
  }

  public BufferedBlockCipher createCipher(BlockCipher engine) {
    BufferedBlockCipher cipher = new PaddedBlockCipher(new CBCBlockCipher(engine));
    return cipher;
  }

  public void runExample() {
    BlockCipher engine = createEngine();
    BufferedBlockCipher cipher = createCipher(engine);
    byte[] key = keyString.getBytes();
    byte[] input = inputString.getBytes();
    cipher.init(true, new KeyParameter(key));
    byte[] cipherText = new byte[cipher.getOutputSize(input.length)];
    int outputLen = cipher.processBytes(input, 0, input.length, cipherText, 0);
  try
  {
    cipher.doFinal(cipherText, outputLen);
  }
  catch (CryptoException ce)
    {
    System.err.println(ce);
    System.exit(1);
    }
  }
}

 

Netty

Client-/Serveranwendungen sind nicht nur schwierig zu programmieren, sondern beanspruchen zum Teil etliche Zeilen an Code. Das NIO-Client-Server-Framework Netty wurde speziell entwickelt, um das Erstellen von Client-/Serveranwendungen zu erleichtern. Im November 2020 erschien das neue Release 4.1.54.

Mit Netty lassen sich sowohl Blocking Sockets als auch Non-Blocking Sockets einsetzen. Ein Vorteil von Non-Blocking IO ist, dass viele Clients zur selben Zeit bedient werden. Außerdem kommen hierbei Channels sowie ByteBuffer-Objekte zum Einsatz. Der Blocking-Modus hingegen bevorzugt Streams sowie Bytearrays. Listing 6 zeigt einen Server mit Non-Blocking IO.

 

 
import java.net.SocketAddress;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
    
public class NettyServer {
  private int port;
  
  public NettyServer(int port) {
    this.port = port;
    System.out.println("server running on port: "+ port);
  }
  
  public void run() throws Exception {
    EventLoopGroup bossGroup = new NioEventLoopGroup();
    EventLoopGroup workerGroup = new NioEventLoopGroup();
    try {
      ServerBootstrap b = new ServerBootstrap();
      b.group(bossGroup, workerGroup)
      .channel(NioServerSocketChannel.class)
      .childHandler(new ChannelInitializer<SocketChannel>() {
        public void initChannel(SocketChannel ch) throws Exception {
          ch.pipeline().addLast(new NettyServerHandler());
          System.out.println("Client-Adress: "+ ch.remoteAddress().getHostString());
        }
      })
      .option(ChannelOption.SO_BACKLOG, 128)          
      .childOption(ChannelOption.SO_KEEPALIVE, true);
      ChannelFuture f = b.bind(this.port).sync();
      f.channel().closeFuture().sync();
    } finally {
      workerGroup.shutdownGracefully();
      bossGroup.shutdownGracefully();
    }
  }
  
  public static void main(String[] args) throws Exception {
    int port = 8080;
    if (args.length > 0) {
       port = Integer.parseInt(args[0]);
    }

    new NettyServer(port).run();
  }
}

 

In Listing 6 wird der Server NettyServer durch die Klasse ChannelFuture an den Port gebunden, der im zugehörigen Konstruktor definiert ist:

ChannelFuture f = b.bind(this.port).sync();

Kanäle zu den Clients werden durch den Aufruf der Methode initChannel erstellt. Zusätzlich gibt die Methode initChannel die Adresse des Clients aus. Außerdem verarbeitet der Server die Clients gleichzeitig, indem Multithreading eingesetzt wird. Dafür ist die Klasse NioEventLoopGroup verantwortlich. Was genau bei Anfragen des Clients erfolgt, regelt der Handler, in diesem Beispiel der NettyServerHandler (Listing 7).

 

 
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

public class NettyServerHandler extends ChannelInboundHandlerAdapter {
  public void channelRead(ChannelHandlerContext ctx, Object msg) {
    ((ByteBuf) msg).release();
  }

  public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
    cause.printStackTrace();
    ctx.close();
  }
}

 

Sobald der Server Daten vom Client erhält, wird die Methode channelRead aufgerufen. Jedoch werden die Daten vom Client in Listing 7 nicht verarbeitet, sondern stattdessen verworfen. Die andere Methode, genannt exceptionCaught, kommt dann zum Einsatz, wenn die Verbindung zum Client abbricht. Sie macht daraufhin den Kanal zum Client dicht.

Der Client selbst wird in Listing 8 realisiert. Der Hostname und die Portnummer des Servers sind schon bekannt, sodass ein Kanal zum Server mittels der Klasse ChannelFuture erstellt wird.

 

 
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.bootstrap.*;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.socket.*;
import io.netty.channel.*;
import io.netty.buffer.ByteBuf;

public class NettyClient {
  public static void main(String[] args) throws Exception {
    String host = "localhost";
    int port =8080;
    EventLoopGroup workerGroup = new NioEventLoopGroup();
    try {
      Bootstrap b = new Bootstrap();
      b.group(workerGroup);
      b.channel(NioSocketChannel.class);
      b.option(ChannelOption.SO_KEEPALIVE, true);
      b.handler(new ChannelInitializer<SocketChannel>() {
        public void initChannel(SocketChannel ch) throws Exception {
          ch.pipeline().addLast(new NettyClientHandler());
        }
      });
      ChannelFuture f = b.connect(host, port).sync();
      f.channel().closeFuture().sync();
    } finally {
      workerGroup.shutdownGracefully();
    }
  }
}

 

Das Verarbeiten der Daten, die der Server an den Client sendet, wird beim Client im Handler namens NettyClientHandler umgesetzt (Listing 9). Dabei gibt die Methode channelRead Nachrichten des Servers als String aus.

 

 
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.*;
import io.netty.buffer.ByteBuf;
public class NettyClientHandler extends ChannelInboundHandlerAdapter {
  public void channelRead(ChannelHandlerContext ctx, Object msg) {
    ByteBuf buffer = (ByteBuf) msg;
    try {
      for (int i = 0; i < buffer.capacity(); i ++) {
        byte b = buffer.getByte(i);
        System.out.println((char) b);
      }
      ctx.close();
    } finally {
       buffer.release();
    }
  }
  public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
    cause.printStackTrace();
    ctx.close();
  }
}

 

JAXB

Mit Jaxb lassen sich XML-Repräsentationen in Java-Objekte umwandeln und umgekehrt. Aktuell ist Jaxb in der Version 2.3.1 verfügbar. Angenommen, ihr braucht eine XML-Datei, die die eigene Musik-CD-Sammlung darstellt. Dann erstellt ihr zunächst eine Java-Klasse vom Typ AudioCD und legt die Attribute der AudioCD fest (Listing 10). Außerdem fügt ihr bei Attributen, die im XML-Dokument erscheinen sollen, XML-Annotationen @Xml … hinzu.

 

 
import java.util.ArrayList;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;

@XmlType( propOrder = { "artist", "title", "year", "songlist"} )
@XmlRootElement(name = "Audiocd")
public class AudioCD {
  private String title;
  private String artist;
  private int year;
  private ArrayList<String> songlist;
  
  @XmlElement(name = "Album")
  public String getTitle() {
    return title;
  }

  public void setTitle(String t) {
    this.title = t;
  }

  @XmlElement(name = "Artist")
  public String getArtist() {
    return artist;
  }

  public void setArtist(String i) {
    this.artist = i;
  }
   
  @XmlElement(name = "Year")
  public int getYear() {
    return year;
  }

  public void setYear(int j) {
    this.year = j;
  }

  @XmlElement(name = "Song")
  public void setSonglist(ArrayList<String> list) {
    this.songlist = list;
  }

  public ArrayList<String> getSonglist() {
    return songlist;
  }
}

 

In diesem Beispiel besteht die CD-Sammlung aus mehreren Audio-CDs. Um die Liste mit den Audio-CDs im XML-Dokument darzustellen, wird eine weitere Klasse namens MusicDB benötigt (Listing 11).

 

 
import java.util.ArrayList;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name = "CD Collection")
public class MusicDB {

  private ArrayList<AudioCD> cdList;
  private String name;
  private String location;

  @XmlElement(name = "CD")
  public void setCdList(ArrayList<AudioCD> l) {
    this.cdList = l;
  }
  public ArrayList<AudioCD> getCdList() {
    return cdList;
  }

  @XmlElement(name = "Music Collection")
  public String getName() {
    return name;
  }

  
  public void setName(String name) {
    this.name = name;
  }

  @XmlElement(name = "Location")
  public String getLocation() {
    return location;
  }

  public void setLocation(String location) {
    this.location = location;
  }
}

 

Listing 12 zeigt, wie Audio-CDs in der CD-Sammlung als ArrayList mit dem Namen mdb gespeichert werden. Außerdem findet in Listing 12 die Konvertierung der Java-Objekte in ein XML-Dokument statt (Abb. 4).

 

 
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;

public class MyMusicDB {
  private static final String MUSICDB_XML = "music-jaxb.xml";
  public static void main(String[] args) throws IOException {
    try {
ArrayList<AudioCD> cds = new ArrayList<AudioCD>();
AudioCD cd1 = new AudioCD();
cd1.setTitle("New Adventures in Hi-Fi");
cd1.setArtist("REM");
cd1.setYear(1996);
ArrayList<String> s1= new ArrayList<>();
s1.add("How the West Was Won");
s1.add("The Wake-Up Bomb");
s1.add("New Test Leper");
s1.add("Undertow");
s1.add("E-Bow the Letter");
s1.add("Leave");
s1.add("Departure");
s1.add("Bittersweet Me");
s1.add("Be Mine");
s1.add("Binky the Doormat");
s1.add("Zither");
s1.add("So Fast, So Numb");
s1.add("Low Desert");
s1.add("Electrolite");
cd1.setSonglist(s1);
cds.add(cd1);

AudioCD cd2 = new AudioCD();
cd2.setTitle("Waking Up");
cd2.setArtist("OneRepublic");
[...]
MusicDB mdb = new MusicDB();
mdb.setName("My Music Collection");
mdb.setLocation("Living Room");
mdb.setCdList(cds);

JAXBContext context = JAXBContext.newInstance(MusicDB.class);
Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
m.marshal(mdb, System.out);
m.marshal(mdb, new File(MUSICDB_XML));
}
    catch( JAXBException e )
    {
       e.printStackTrace();
    }
  }
}

 



Abb. 4: Nach der Konvertierung kann die XML-Darstellung der CD-Sammlung betrachtet werden

 

JSON Simple

Manchmal sind selbst einfache Tasks wie das Erstellen von JSON-Objekten in Java ziemlich kompliziert. Dank Googles Library lässt sich dieser Code vereinfachen. JSON Simple ist zurzeit in der Version 1.1.1 erhältlich, wurde jedoch seit 2012 nicht mehr aktualisiert. In Listing 13 ist zu sehen, wie ein JSON-Objekt erstellt und anschließend mit Daten befüllt wird.

 

 
import org.json.simple.JSONObject;

public void setJSONObjectParams() {
  JSONObject jObj = new JSONObject();
}

public void addToJson(JSONObject jObj, String key, String value){
  jObj.put(key,value);
}

 

Darüber hinaus kann JSON Simple JSON-Objekte parsen und JSON-Arrays erstellen. Die JSON-Objekte lassen sich verschachteln, indem das Wurzelelement selbst ein JSON-Objekt ist. Beim abzuspeichernden Schlüssel-Wert-Paar wird als Wert ein anderes JSON-Objekt eingefügt, wobei der Schlüssel einem String entspricht.

The post Zehn Must-have-Java-Bibliotheken appeared first on JAX.

]]>