HttpClient – Migration auf Java 11

In den letzten beiden Folgen der Java Perlen haben wir uns mit dem httpClient API unter Java 9 beschäftigt. Mit Java 11 ist das httpClient API nun offizieller Bestandteil des JDKs. Wir möchten uns diesmal anschauen, was angepasst werden muss, damit unser Code unter Java 11 läuft.


1. Offizielles Modul

In Java 9 ist das httpClient API im JDK internen Modul jdk.incubator.httpclient implementiert. Die Importe sehen in Java 9 so aus:

Mit Java 11 ist das httpClient API nun im offiziellen java.base JDK Modul. Das bedeutet für uns, dass der Umweg über ein eigenes Modul nicht mehr zwingend ist. Mit folgenden Schritten sollten wir Java 11 kompatibel werden:

  • Da der Modul Descriptor (module-info.java) optional ist, können wir diesen löschen.
  • In der IDE einfach die Imports löschen und automatisch neu generieren lassen. Die Import sehen unter Java 11 nun so aus:

… und leider sind wir noch nicht fertig. Unser Code Beispiele haben noch an diversen Stellen Compile Errors. Dies liegt daran, dass es mit Java 11 kleinere Anpassungen im API gibt.

2. HttpResponse Changes

Wir starten mit dem “Hello World” Beispiel, welches einen HTTP GET Request macht. Die Erstellung des HttpRequest ist immer noch gleich. Die send() Methode des HttpClients möchte neben dem HttpRequest einen BodyHandler haben (gleich wie in Java 9). Neu ist der BodyHandler aber nicht mehr eine Klasse, sondern ein Interface. Konkrete Implementationen findet man dann in der Hilfsklasse BodyHandlers.

(Java 9)
String pageUrl = "https://www.puzzle.ch/de"
HttpRequest request = HttpRequest.newBuilder(new URI(pageUrl))
                             .GET()
                             .build();
HttpResponse response = HttpClient.newHttpClient().send(
  request,
  HttpResponse.BodyHandler.asString());

Aber was genau ist ein BodyHandler und wie wird er verwendet?

public interface BodyHandler {
    public BodySubscriber apply(ResponseInfo responseInfo);
}
  • Der BodyHandler ist ein Handler für die HttpResponse. Er analysiert den Response Code und die Headers (vor dem Empfangen der Daten) und erstellt einen BodySubscriber.
  • Der BodySubscriber verarbeitet die “rohen” Daten (bytes) und erstellt daraus Java Daten Typen. Je nach Implementation kann das ein String, ein File etc. sein.
  • Konkrete Implementationen des BodyHandler Interfaces gibt es in der Klasse BodyHandlers.
public static class BodyHandlers {
	public static BodyHandler ofString() { … }
	public static BodyHandler ofFile(Path file) { … }
	public static BodyHandler<byte[]> ofByteArray() { … }
}

Unser “Hello World” sieht in Java 11 nun folgendermassen aus:

(Java 11)
String pageUrl = "https://www.puzzle.ch/de"
HttpRequest request = HttpRequest.newBuilder(new URI(pageUrl)) 
				.GET() 
				.build();

HttpResponse response = HttpClient.newHttpClient().send( 
  request, 
  HttpResponse.BodyHandlers.ofString());}

3. HttpRequest Changes

Wir hatten uns auch angeschaut, wie man mit dem HttpClient API POST Requests machen kann. Dazu haben wir folgenden Code in Java 9 implementiert

(Java 9)
String data = "Lorem ipsum dolor";
HttpRequest request = HttpRequest.newBuilder()
   .uri(new URI(pageUrl))
   .POST(HttpRequest.BodyProcessor.fromString(data))
   .build();

Auch hier hat sich das API etwas verändert. Im Details sieht das so aus:

Im HttpRequest.Builder gibt es (unter anderem) Methoden um einen POST oder PUT Request zu machen. Beide Methoden haben als Parameter einen BodyPublisher. Ein BodyPublisher ist quasi das Gegenstück zu einem BodySubscriber. Dieser wandelt Java Objekte um in bytes, die dann in einem Request mitgeschickt werden können.

public interface Builder {
 public Builder POST(BodyPublisher bodyPublisher);
 public Builder PUT(BodyPublisher bodyPublisher);
}

Die Klasse BodyPublishers bietet verschiedene Implementation von BodyPublisher an.

public static class BodyPublishers {
 public static BodyPublisher ofString(String body) { … }
 public static BodyPublisher ofByteArray(byte[] buf) { … }
 public static BodyPublisher ofFile(Path path) throws FileNotFoundException { ..}
}

Mit diesen Anpassungen sieht unser POST Bespiel nun so aus:

(Java 11)
String data = "Lorem ipsum dolor";
HttpRequest request = HttpRequest.newBuilder()
  .uri(new URI(pageUrl))
  .POST(HttpRequest.BodyPublishers.ofString(data))
  .build();

4. Redirect

Der HttpClient bietet Funktionalität für “URL Redirection” an. Wenn beispielsweise eine Seite nicht mehr existiert (z.B. die von Sun) wird man direkt weitergeleitet auf eine andere Seite (die von Oracle). Dazu hatten wir folgendes Beispiel implementiert.

(Java 9)
HttpResponse response = HttpClient.newBuilder()
    .followRedirects(HttpClient.Redirect.SAME_PROTOCOL)
    .build()
    .send(request, HttpResponse.BodyHandlers.ofString());

In Java 11 wurde Redirect.SAME_PROTOCOL gestrichen. Mit Redirect.ALWAYS funktioniert das Beispiel wieder.

5. Cookies

Auch bei der Arbeit mit Cookies gibt es eine Anpassung im API. In Java 9 haben wir einen CookieManager verwendet.

(Java 9)
CookieManager cookieManager = new CookieManager();

HttpResponse firstResponse = HttpClient.newBuilder()
  .proxy(ProxySelector.of(new InetSocketAddress("localhost", 8080)))
  .cookieManager(cookieManager)
  .build().send(request, HttpResponse.BodyHandler.asString());

In Java 11 verwenden wir einen CookieHandler. Da CookieManager eine Erweiterung von CookieHandler ist, können wir den Java 9 Code direkt in Java 11 verwenden. Nur der Name der Methode ändert sich von cookieManager() zu cookieHandler()

public abstract class CookieHandler { ... }
public class CookieManager extends CookieHandler { ... }

Und unser Beispiel sieht dann unter Java 11 so aus:

(Java 11)
CookieManager cookieManager = new CookieManager();
HttpResponse firstResponse = HttpClient.newBuilder()
                                             .cookieHandler(cookieManager)
                                             .build().send(request, HttpResponse.BodyHandlers.ofString());

6. Fazit und Ausblick

Zusammenfassend kann man sagen:

  • Mit Java 11 ist das HttpClient API nun offizieller Bestandteil des JDKs.
  • Die Nutzung ist einfacher geworden, da der Umweg über ein eigenes Modul nicht mehr zwingend ist.
  • Das API wurde gegenüber Java 9 an diversen Stellen nur leicht angepasst.

Zusätzlich gibt es Erweiterungen, die den HttpClient in das Flow API (neu in Java 9) integrieren und somit das API in die “ReactiveX” Welt integrieren. Dies werden wir uns in einer späteren Folge der Java Perlen anschauen.

Und ganz zum Schluss: Wer selber mal mit dem HttpClient API experimentieren möchte, findet die Beispiele auch für Java 11 in einem neuen Repo.

Referenzen

Kommentare sind geschlossen.