Tutorial

RESTful Web Services mit JAX-RS: Nicht nur bereitstellen, sondern nutzen!

Matti Tahvonen

© istockphoto.com/ma_rish

Java ist wahrscheinlich die üblichste Plattform, um REST-­Services anzubieten. Aber in vielen Java-Anwendungen sollen diese natürlich auch benutzt werden. Und es kann auch passieren, dass REST-Services sich auf weitere REST­-Services stützen, um ihre Daten bereitzustellen.

Ein typischer Fehler von uns Java-­Programmierern ist es, alles selbst zu tun. Wir können etwa URL.openStream() ausführen, die Antwort in einen String lesen und die Daten dann händisch aus dem String parsen. Das ist auf jeden Fall möglich und sogar ziemlich leicht, selbst mit nur den Standard­-JDK­Libraries. Aber es gibt bessere Wege, zum Ziel zu gelangen.

Das Java­-Ökosystem hat eine Menge exzellenter Libraries, viele wirklich gut durchdachte Standards und oftmals sogar mehrere Implementierungen derselben, die zueinander im Wettbewerb stehen. JAX-­RS ist eine solche Library, die REST­-Services zur Verfügung stellt. Das ist bei den Java­-EE­-Entwicklern wohlbekannt. Aber die Spezifikation enthält auch ein etwas weniger bekanntes Programmierinterface zum Benutzen von REST­-Services. Darauf zurückzugreifen hilft uns, Code schneller zu schreiben und leichter zu warten.

Meine Beispielanwendung ist eine kleine Java­-EE­-Anwendung, die Wettervorhersagen von openweathermap.org in POJOs (Plain Old Java Objects) einliest und sie dann mit einer einfachen Vaadin-­Benutzeroberfläche im Browser anzeigt. Der eigentliche Kern dieses Tutorials ist keinesfalls Java-­EE­- oder auch nur Vaadin-spezifisch. Es geht darum, eine Menge Boilerplate-Code zu vermeiden, um sich auf das Wesentliche zu konzentrieren. Obwohl JAX-­RS Teil der Java-­EE­-Spezifikation ist, ist es nicht von anderen Teilen der Java EE abhängig. Das heißt, wenn eine Applikation nicht in einem Java-EE­-Container läuft, kann man einfach eine JAX­-RS­-Implementierung wie Jersey und eine passende Object Mapper Library hinzufügen und das Beispiel entsprechend seiner Bedürfnisse anpassen. Wenn man mit einem Spring­-basierten Stack arbeitet, sollte man sich stattdessen vielleicht besser das Rest-Template-API ansehen, das so ziemlich dasselbe macht wie ein JAX­-RS-Client. Der Prozess lässt sich in drei Schritte aufspalten: die Modellierung, die Verarbeitung und die Benutzung.

Schritt 1: Modellierung der Daten

Üblicherweise stellt der Dienst Daten entweder im XML­- oder im JSON­-Format bereit. Wenn die Antworten nun nicht völlig trivial sind (z. B. eine Liste von Strings), spart man keine Zeit, wenn man direkt auf sie zugreift. Low­-Level­-Programmierschnittstellen oder eine Map-­basierte Repräsentation für JSON zu benutzen ist möglich, aber das verbessert nicht gerade die Lesbarkeit des Codes. Manchmal hat man Zugang zu dem originalen Datenmodell, das dort benutzt wird, wo die Daten herkommen. Aber POJOs aus XML oder JSON zu rekonstruieren ist schnell und einfach zu bewerkstelligen.

Kleinere Modelle kann man händisch schnell rekonstruieren, aber Werkzeuge erhöhen die Produktivität an dieser Stelle immens. Um das vollständige Modell für dieses Beispiel zu generieren, habe ich eine Onlinedienst benutzt. Alles, was ich dafür getan habe, war ihn mit einer beispielhaften JSON­-Antwort unseres Service durch Kopieren und Einfügen zu füttern. Ich habe die Checkboxen entsprechend meiner Bedürfnisse angepasst und dann die generierten Artefakte in mein Projekt kopiert. Ich musste keine Annotationen oder andere Hinweise für die Object Mapper Libraries lesen. In vielen Fällen sind wohlgeformte Daten mit einer sauberen Namenskonvention genug. Die dem Dienst zugrunde liegenden Werkzeuge stehen auch für den lokalen Gebrauch zur Verfügung.

Schritt 2: Holen der Daten

Das eigentliche Benutzen der Clienprogrammierschnittstelle des JAX-­RS ist leicht. Dennoch habe ich diesen Teil in eine Serviceklasse ausgelagert, um ihn vom eigentlichen Code für die Benutzeroberfläche zu trennen. Jener Code braucht nicht zu wissen, ob er nun einen REST-­Service, einen anderen Web Service oder eine Datenbank benutzt. Die öffentliche Programmierschnittstelle zeigt ihm nur die rekonstruierte WeatherResponse-­Klasse.

Dreh­ und Angelpunkt der Clientprogrammierschnittstelle des JAX-­RS sind vor allem Client­ und WebTarget-Objekte. Das Clientobjekt behandelt die gesamte Kommunikation. Obwohl die Instanzen nicht gerade schwergewichtig sind, habe ich nur eine Instanz pro Serviceklasse erzeugt, weil empfohlen wird, möglichst wenige Instanzen zu benutzen. In unserem Fall braucht der Client keine spezielle Konfiguration. Also holen wir einfach eine Instanz mit Default-­Einstellungen vom ClientBuilder:

 private Client client; private WebTarget target;

@PostConstruct protected void init() {
  client = ClientBuilder.newClient();
  // query params: ?q=Turku&cnt=10&mode=json&units=metric
  target = client.target("http://api.openweathermap.org/data/2.5/forecast/ daily")
  .queryParam("cnt", "10")
  .queryParam("mode", "json")
  .queryParam("units", "metric");
}
 

WebTarget-­Objekte sind „immutable“ (also nach der Erzeugung unveränderlich) mit modellspezifischen URIs zu dem Service, auf den man zugreift. In der init­-Methode sieht man, wie das sprechende Programmierinterface („Fluent-API“, hier zur Verkettung von Funktionsaufrufen) benutzt werden kann, um „statische“ Parameter aufeinanderzustapeln und das Zwischenziel als Feld zu speichern. In der Methode mit der Geschäftslogik brauchen wir dann nur noch den dynamischen Parameter anzuhängen und den eigentlichen Aufruf zu machen:

 public ForecastResponse getForecast(String place) {
  return target.queryParam("q", place)
  .request(MediaType.APPLICATION_JSON)
  .get(ForecastResponse.class);
}
 

In der request-­Methode kann man explizit nach einem bestimmten Typ von Antwort fragen. Das ist aber in unserem Fall unnötig, da wir dies ja bereits als dienstspezifischen Parameter festgelegt haben. Die eigentliche GET­Anfrage (Request) wird in einer entsprechend benannten Methode erledigt. An dieser Stelle nutzen wir dann das rekonstruierte Datenmodell aus Schritt 1. Statt das Response­-Objekt händisch zu inspizieren, können wir hier nun einfach den Klassentyp des Response­-Modells als Parameter übergeben.

Hinter den Kulissen konvertiert eine Object Mapper Library wie Jackson automatisch das rohe – in diesem Fall – JSON in das rekonstruierte fachliche Modell. Wenn die Schnittstelle in einer Java­-SE­Laufzeitumgebung zum Einsatz kommt, muss die Object Mapper Library zusammen mit der JAX­-RS­Programmierschnittstelle konfiguriert werden. Man beachte dabei den speziellen Typ GenericType, der in manchen Fällen benutzt werden kann, um sich die Rekonstruktion von einfachen Typen wie Listen von Strings oder Listen der fachspezifischen Datentypen zu ersparen.

Andere HTTP­-Methoden wie POST und PUT werden auch auf natürliche Weise unterstützt. Man kann seine Nutzdaten mit dem gleichen automatischen POJO­-Mapping schicken, nur eben in die andere Richtung. Dazu muss man einfach die Nutzdaten in eine Entity einpacken, indem man deren statische Fabrikmethoden benutzt.

Schritt 3: Benutzen der Daten

POJOs mit so ziemlich jedweder Java-­Technologie zu benutzen, ist so grundlegend, dass ich eine gründliche Besprechung hier überspringe. Um aus dem Beispiel eine lauffähige Anwendung zu machen, habe ich den Dienst in eine Vaadin­-Benutzeroberfläche eingeklinkt. Aus dem Vaadin-UI kann man drei vordefinierte Städte auswählen. Die Funktionalität in der ForecastDisplay­-Klasse iteriert dann über die täglichen Vorhersagen und zeigt die Daten in für Menschen lesbarer Form an.

Die Grundlagen, JAX-­RS-Clientprogrammierschnittstellen zu benutzen, sollten jetzt geklärt sein. Mehr Details findet man in den Javadocs oder in implementierungsspezifischen Handbüchern.

Um diese Hilfe nun einfach einmal auszuprobieren, schlage ich vor, mein Beispielprojekt in seine Lieblings-­IDE zu importieren und loszulegen!

Verwandte Themen:

Geschrieben von
Matti Tahvonen
Matti Tahvonen
Matti Tahvonen ist kein Unbekannter bei Vaadin: Seit den Anfängen der JavaScript-Programmierung bis in die GWT-Ära hinein hat er das Framework mit­ und weiterentwickelt. Er ist mit einer ganzen Reihe offizieller und inoffizieller Add­ons in der Vaadin Directory vertreten. Heute verbringt er einen Großteil seiner Zeit damit, über die neuesten Technologien und deren Zusammenspiel mit Vaadin zu informieren. Dabei bringt er sein Expertenwissen auch in die Vaadin GmbH ein und stellt sicher, dass auch die deutschsprachigen Kunden bestens über den Einsatz von Vaadin, Java EE, Spring und das Thema User Interfaces informiert sind.
Kommentare

Hinterlasse einen Kommentar

Hinterlasse den ersten Kommentar!

avatar
400
  Subscribe  
Benachrichtige mich zu: