Erhältlich ab: August 2018
Auf der JAX 2018 präsentierte Mike Milinkovich das neue Logo für Javas Enterprise-Version. Jakarta EE ziert seitdem ein Segelboot. Mein erster Gedanke dazu war: „I’m sailing“, und ich hatte Rod Stewarts Song im Ohr. Abseits von Rod Stewart finde ich das neue Logo für Java EE sehr passend. Ein Segelboot symbolisiert Aufbruch und Vorwärtsgewandheit. Genau das will die Eclipse Foundation ausdrücken. „Jakarta EE is about how to get the technology forward!“, sagt Mike Milinkovich im Interview auf Jaxenter.de (https://jaxenter.de/jakarta-ee-cloud-native-java-ee-70336).
Java EE befindet sich schließlich gerade tatsächlich auf einer Reise, unterwegs von Oracle in Richtung Eclipse Foundation. Das Ziel auf lokaler Ebene kennen wir. Aber nicht nur das. Eclipse schreibt im Zusammenhang mit Jakarta EE zwei Dinge ganz groß: Community und Open Source. Allen voran sollen die Entwickler bei der Zukunft von Jakarta EE mit im Boot sitzen. Ein Beispiel ist die Namensfindung. Die Community hat abgestimmt. Aber auch in anderen Dingen ist Mitreden eindeutig erwünscht. Der neue Community Process soll den klassischen JCP ersetzen. Hier soll der Open-Source-Gedanke Wirklichkeit werden. Innovation soll transparenter und schneller auf die Straße.
Das neue Motto in der Java-Enterprise-Welt heißt „Auf zu neuen Ufern“, oder wie es Thilo Frotscher in seinem Artikel zu MicroProfile auf Seite 44 formuliert: „Mit vollen Segeln voraus“. Es tut sich etwas – so viel ist klar. Allerdings sollte auch bei aller Aufbruchstimmung rund um das Thema eines klar sein: Etwas so lange Gewachsenes und Schwergewichtiges wie Enterprise Java zu transportieren, braucht eben Zeit. Wer den Prozess gerne beobachten oder selber mitwirken will, kann dies etwa auf der Jakarta-EE-Webseite https://jakarta.ee oder natürlich im Java Magazin tun.
Ich wünsche viel Freude beim Lesen!
Java unterscheidet sich von anderen Programmiersprachen insofern, als es sich dabei nicht nur um eine normale Programmiersprache, sondern vielmehr um ein ganzes Ökosystem handelt. Das hier besprochene, bei Springer mittlerweile in der zehnten Auflage erschienene Werk möchte Quereinsteigern mit Programmiererfahrung den Weg in dieses Ökosystem ebnen.
Nach einer einleitenden Erläuterung von Konzepten wie der virtuellen Maschine, IDE und Co. geht das zweite Kapitel auf alle syntaktischen Besonderheiten ein. Zwar ist es unüblich, dass ein Werk Variablentypen, Operatoren, Kontrollstrukturen und diverse andere Themen so kompakt abhandelt, wer jedoch Vorkenntnisse mitbringt, sollte hiermit keine Probleme haben.
Die tendenzielle inhaltliche Überfrachtung setzt sich im dritten und vierten Kapitel fort. Während das dritte Kapitel auf objektorientierte Programmierung eingeht, thematisiert das vierte detailliert Exceptions. Ein Leser, der von nicht objektorientierten Programmiersprachen umsteigt, dürfte in Kapitel 4 zusätzliche Informationen zum Thema OOP vermissen.
Zum Verständnis von Java ist es grundsätzlich hilfreich, eine Gruppe von in der Standardbibliothek vorkommenden Klassen zu kennen. Das fünfte Kapitel versucht sich daran, dieses Thema zu erschließen. Abgesehen von diversen Klassikern findet sich in diesem Abschnitt auch eine kurze Besprechung der Internationalisierung, die im heutigen multipolaren IT-Umfeld ganz gewiss nicht fehl am Platz ist.
Kapitel 6 zu generischen Typen und Kapitel 7 zu Lambdas sowie Streams dienen als Vorbereitung für die darauffolgenden Exkurse in die Welt der großen Datenhaltung. Diese nehmen ihren Anfang im achten Kapitel, das zunächst auf die Klasse File eingeht, um im Anschluss Methoden zur Serialisierung und zur Handhabung von Dateisystemen als Ganzes vorzustellen. Abts beweist hier Liebe zum Detail – so geht er beispielsweise auch darauf ein, wie mit komprimierten Dateien umzugehen ist.
Im neu hinzugekommenen Kapitel setzt sich der Autor mit Multithreading auseinander. Auch hier gilt, dass die Exkurse zwar ausreichend sind, eine theoretische Einführung in die Thematik allerdings auf keinen Fall ersetzen können.
Wer ein Lehrbuch zu Java schreibt und auf das Design von Benutzerschnittstellen eingeht, hat in Sachen Stacks die Qual der Wahl. Abts entscheidet sich für einen umfassenden Ansatz, der sowohl AWT als auch JavaFX vorstellt. Die Besprechung von JavaFX ist lohnend, da das darauffolgende Kapitel zu JDBC auch darauf eingeht, wie sich aus der Datenbank kommende Informationen ansprechend in einem Diagramm präsentieren lassen.
Der dritte Teil des Werks setzt sich mit Enterprise-Anwendungen auseinander. Neben einer Besprechung von TCP-IP findet sich ein Kapitel, das mehrschichtige Architekturen anhand eines kleinen Programmbeispiels demonstriert. Im Anschluss folgen Kapitel zum Persistenz-API, objektorientierten Datenbanken und der Modularisierung unter Nutzung des in Java 9 neu eingeführten Modulsystems.
Der didaktische Aufbau von „Grundkurs JAVA“ erinnert stark an Klassiker wie Guido Krügers Einführung in die Programmiersprache C. So findet sich am Ende eines jeden der reich bebilderten Kapitel eine Gruppe von Übungen, die teilweise durchaus knackig ausfallen.
„Grundkurs JAVA“ dürften all jene sofort ins Herz schließen, die von einer anderen objektorientierten Programmiersprache auf Java umschulen möchten. Wer beispielsweise Physiker beschäftigt, die mit Modula oder Delphi programmieren, findet mit diesem Werk eine Zeitmaschine, die direkt in die Zukunft führt.
Dietmar Abts
Grundkurs JAVA
Von den Grundlagen bis zu Datenbank- und Netzanwendungen
647 Seiten, 37,99 EuroSpringer Vieweg, 10. Auflage 2018eBook ISBN: 978-3-658-21907-9Softcover ISBN: 978-3-658-21906-2
Die MVC-1.0-Spezifikation (aka JSR 371) hatte es bisher nicht gerade einfach. Ursprünglich war sie als Teil von Java EE 8 geplant, um eine leichtgewichtige Alternative zum komponentenbasierten JSF-Framework zu bieten. Im Zuge der von Oracle geplanten Neuausrichtung der Java-Enterprise-Plattform auf Cloud-Computing wurde die Spezifikation aber wieder entfernt.
Anstatt MVC 1.0 komplett zu verwerfen, übernahm Ivar Grimstad das Projekt und agiert seitdem mit der Unterstützung von Christian Kaltepoth unabhängig von Oracle als Specification Lead [1]. Langfristig soll die Spezifikation an das EE4J-Projekt übertragen werden und so wieder Teil des gesamten „Standards“ werden. Voraussetzung dafür ist aber laut Grimstad, dass MVC 1.0 zuvor einen finalen Releasestatus erreicht. Das soll in Q2 2018 der Fall sein [2].
MVC 1.0 ermöglicht die Entwicklung Action-basierter Webanwendungen. Im Gegensatz zu komponentenbasierten Webframeworks wie JSF, bei denen Webtechnologien wie HTML und JavaScript sowie Interaktionen mit HTTP weitestgehend vom Entwickler versteckt sind, wird bei Action-basierten Frameworks vergleichsweise wenig abstrahiert. Vielmehr finden sich Entwickler in der klassischen, Request- und Response-basierten Webentwicklung wieder.
Der Vorteil des Action-basierten Ansatzes liegt vor allem in der Leichtgewichtigkeit und Flexibilität. Durch die geringe Abstraktion sind diese Art von Webframeworks zumeist weniger komplex als komponentenbasierte Ansätze wie JSF. Zudem lassen sich beim Action-basierten Vorgehen beliebige architektonische und technische Ansätze kombinieren, weil die Frameworks in der Regel flexibel sind und nur wenig vorschreiben. Der Preis der geringen Abstraktion liegt aber im Umkehrschluss darin, dass Entwickler sich wieder vermehrt mit Webtechnologien auseinandersetzen müssen. Zudem kann der programmatische Aufwand höher sein, als bei komponentenbasierten Webframeworks.
Action-basierte Ansätze eignen sich auch bei der Entwicklung von Single Page Applications (SPAs). Schließlich wird hier ein Großteil der Anwendung erst auf dem Client gerendert. Die Aufgaben des serverseitigen Webframeworks sind also eher überschaubar. Leichtgewichtige und flexible Frameworks wie MVC 1.0 passen deshalb besonders gut zu SPAs.
Im Gegensatz zu manch anderer Spezifikation ist die von MVC 1.0 nicht sehr umfangreich [3]. Die rein technische Beschreibung des Frameworks ist auf nur knapp über 30 Seiten zusammengefasst. Das hat zwei Gründe: Zum einen ist das Featureset von MVC 1.0 klein, das Framework muss sich schließlich um vergleichsweise wenige Dinge kümmern. Zum anderen basiert MVC 1.0 zum Großteil auf den bestehenden Standards JAX-RS, CDI und Bean Validation. Die Spezifikation ist also hauptsächlich eine Kombination aus etablierten Technologien und benötigt deshalb nur wenige neue Interfaces und Annotationen. Die Grundlage für MVC 1.0 bildet JAX-RS. Genau wie bei JAX-RS steht auch bei MVC 1.0 die HTTP-Kommunikation im Vordergrund. Ein Großteil der Interfaces und Annotationen kann hier deshalb einfach wiederverwendet werden. Wie bei allen neueren EE-APIs ist zudem der CDI-Standard zwingende Voraussetzung für die Verwendung von MVC 1.0. CDI wird beispielsweise für die Integration der Model-Schicht verwendet. Der Bean-Validation-Standard kommt bei der serverseitigen Validierung zum Einsatz.
Das Herzstück in MVC 1.0 bilden die Controller. Hier werden HTTP-Anfragen entgegengenommen, Parameter validiert, Model-Manipulationen initiiert und schlussendlich das Rendern einer Antwort veranlasst. Technisch gesehen ist ein Controller nichts weiter als eine JAX-RS-Ressourcenmethode, die mit der MVC-1.0-spezifischen Annotation @Controller versehen ist. Diese Annotation kann sowohl an Klassen als auch an einzelne Methoden geschrieben werden. Letzteres erlaubt die Erstellung von hybriden Controllern, die sowohl Controller-Methoden als auch herkömmliche JAX-RS-Ressourcen beinhalten (Listing 1).
Der Rückgabewert einer Controller-Methode wird als Pfad zu einer View-Datei interpretiert und standardmäßig relativ zum /WEB-INF/views/ Ordner aufgelöst. Es gibt insgesamt drei verschiedene Möglichkeiten, den Rückgabewert einer Controller-Methode zu definieren (Listing 2).
Wie eingangs erwähnt, ist CDI ein zwingender Bestandteil von MVC 1.0. Jede Controller-Klasse muss deshalb CDI-managed sein. Die Lebensdauer von Controllern ist standardmäßig „per request“ (CDI-@RequestScoped), es können aber auch andere CDI-Scopes verwendet werden (z. B. @SessionScoped-Controller für statusvolle Anwendungen).
Listing 1: Simple MVC 1.0 Controller
@Path("/")
public class HelloController {
@Controller
@GET
@Path("view")
public String getIndexView() {
//MVC Controller method.
//Returns path to view & sends HTML.
return "index.jsp";
}
@GET
@Path("data")
@Produces(MediaType.APPLICATION_JSON)
public Response getJsonData() {
//JAX-RS method. Sends JSON.
return Response.ok(…).build();
}
}
Listing 2: Possible return types of an MVC 1.0 Controller
@Controller
@Path("/")
public class HelloController {
@GET
@Path("void")
@View("hello.jsp")
public void helloVoid() {
}
@GET
@Path("string")
public String helloString() {
return "hello.jsp";
}
@GET
@Path("response")
public Response helloResponse() {
return Response.status(Response.Status.OK)
.entity("hello.jsp")
.build();
}
}
Controller sind dafür verantwortlich, die Views und Datenmodelle (Models) zu kombinieren, um das Rendern dynamischer Webanwendungen zu ermöglichen. MVC 1.0 unterstützt zwei Arten von Models: CDI-@ Named-Beans und das MVC-1.0-eigene Models-Interface.
CDI-@Named-Beans können, wie es beispielsweise auch in JSF möglich ist, dazu verwendet werden, Daten in den jeweiligen Views zur Verfügung zu stellen. Dazu lassen sich beliebige CDI-@Named-Beans in einen Controller injizieren und von dort aus manipulieren (Listing 3). Voraussetzung für diese Art von Models ist allerdings, dass die jeweilig verwendete View-Engine @ Named-Beans unterstützt (z. B. JSP oder Facelets).
Auch das Models-Interface lässt sich dazu verwenden, Daten an den View zu übermitteln. Dieses spezielle Interface, das eine Art von String-Object-Map repräsentiert, kann ebenfalls mithilfe von CDI in einen Controller injiziert und dort manipuliert werden (Listing 4).
Laut der MVC-1.0-Spezifikation sind View Engines nicht dazu verpflichtet, CDI-@Named-Beans zu unterstützen. Trotzdem ist deren Verwendung, sofern möglich, der des Models-Interface vorzuziehen. CDI-Beans sind durch die verschiedenen Scopes (z. B. @RequestScoped, @SessionScoped) viel flexibler und führen außerdem zu einer klaren Trennung der Model- und Controller-Schicht.
Listing 3: CDI-„@Named“-Bean as model
@Named
@SessionScoped
public class GreetingBean {
private String message;
//getter + setter...
}
@Controller
@Path("hello")
public class HelloController {
@Inject
private GreetingBean greeting;
@GET
public String hello() {
//Can be used as "greetingBean.message" in a view
greeting.setMessage("Hello there!");
return "hello.jsp";
}
}
Listing 4: „Models“-Interface as model
@Controller
@Path("hello")
public class HelloController {
@Inject
private Models models;
@GET
public String hello() {
//Can be used as "greeting.message" in a view
models.put("greeting", new Greeting("Hello there!"));
return "hello.jsp";
}
}
In MVC 1.0 ist nicht festgelegt, welche Templating Engine zum Rendern des dynamischen HTML auf Basis der Models verwendet wird. Standardmäßig müssen jedoch JSP und die aus JSF bekannte Templating Engine Facelets zur Verfügung stehen. Listing 5 zeigt, wie in den Views auf die Daten des Models zugegriffen werden kann. Als Templating Engine kommt in diesem Beispiel JSP zum Einsatz.
Listing 5: Access models in JSP view
<!DOCTYPE html>
<html>
<head>
<title>Hello</title>
</head>
<body>
<!-- Access Models-Interface -->
<h1>${greeting.message}</h1>
<!-- Access CDI-@Named-Bean -->
<h1>${greetingBean.message}</h1>
</body>
</html>
Mit der @FormParam-Annotation, die Teil des JAX-RS-Standards ist, lassen sich im Request übermittelte Parameter eines Formulars extrahieren. Zudem ist es möglich, mithilfe der @BeanParam-Annotation mehrere Parameter in einer Klasse zusammenzufassen. Für die Validierung der Request-Parameter wird der Bean-Validation-Standard in Kombination mit der MVC 1.0 spezifischen @MvcBinding-Annotation und dem BindingResult-Interface verwendet (Listing 6).
Für Felder, die mit der @MvcBinding-Annotation versehen sind, werden etwaige Validierungsfehler in einer für den Request gültigen Instanz des BindingResult-Interface hinterlegt. Dieses kann mit CDI in einen Controller injiziert und für die Fehlerbehandlung verwendet werden. Validierungsfehler, die nicht durch die @MvcBinding-Annotation gemappt sind, enden in einer ConstraintViolationException. Diese kann, wie bereits aus JAX-RS bekannt, global mithilfe eines ExceptionMappers behandelt werden.
Listing 6: Validation in MVC 1.0
public class FormDataBean {
@MvcBinding
@FormParam("age")
@Min(18)
private long age;
//getter + setter...
}
@Controller
@Path("form")
public class FormController {
@Inject
private BindingResult br;
@POST
public Response formPost(@Valid @BeanParam FormDataBean form) {
if (br.isFailed()) {
return Response.status(BAD_REQUEST)
.entity("error.jsp").build();
}
return Response.status(OK).entity("index.jsp").build();
}
}
MVC 1.0 unterstützt von Haus aus Mechanismen, um Redirects zu initiieren und zu behandeln. Mithilfe von Redirects können Anfragen an eine Ressource zu einer anderen weitergeleitet werden. Beispielsweise lässt sich so das Post/Redirect/Get-Pattern umsetzen, das beim Log-in-Prozess (z. B. Umleiten vom LoginController zum HomeController) oder nach dem Absenden eines Formulars (Vermeidung von erneuten Submits) verwendet werden kann.
Um einen Redirect zu initiieren, muss der zurückgegebene Pfad eines Controllers mit dem Präfix redirect: beginnen (Listing 7). MVC 1.0 liefert zudem einen neuen CDI-Scope mit dem Namen @RedirectScoped. CDI-Beans, die damit annotiert sind, speichern Daten für genau einen Redirect und sind somit ein wenig mächtiger als @ RequestScoped-Beans.
Listing 7: Redirects in MVC 1.0
@Controller
@Path("submit")
public class MyController {
@POST
public String post() {
return "redirect:/submit";
}
@GET
public String get() {
return "mybean.jsp";
}
}
MVC 1.0 bietet Mechanismen, um Attacken wie Cross-site Request Forgery (CSRF) und Cross-site Scripting (XSS) zu verhindern. Allerdings müssen diese erst aktiviert bzw. die APIs explizit verwendet werden. Eine MVC-1.0-Anwendung ist also nicht automatisch gegen CSRF- und XSS-Angriffe geschützt.
Für mehrsprachige Anwendungen gibt es in MVC 1.0 die Möglichkeit, den Ländercode (Locale) aus einem Request zu extrahieren. Dazu kann mithilfe von CDI das MvcContext-Interface in einen Controller injiziert werden. Das ermöglicht unter anderem den Zugriff auf das Locale-Object des aktuellen Request. So lassen sich Übersetzungen oder Zahlen- und Datumsformate dynamisch anpassen (Listing 8). Die zu verwendende Locale wird ohne weiteres aus dem Accept-Language-Header extrahiert, der im Normalfall vom Browser mitgesendet wird.
Listing 8: Internationalization in MVC 1.0
@Controller
@Path("/foobar")
public class MyController {
@Inject
private MvcContext mvc;
@GET
public String get() {
Locale locale = mvc.getLocale();
NumberFormat format = NumberFormat.getInstance(locale);
}
}
Mit MVC 1.0 wurde das Rad keineswegs neu erfunden. Spring MVC ist beispielsweise seit Jahren mit ähnlichem Funktionsumfang der große Vertreter Action-basierter MVC-Frameworks im Java-Umfeld. Trotzdem hat MVC 1.0 durchaus eine Daseinsberechtigung – es fehlt in EE schließlich eine leichtgewichtige Alternative zu JSF, die im Zeitalter von Microservices und Single Page Applications dringend notwenig ist.
Die Spezifikation von MVC 1.0 ist zwar sehr schlank, liefert aber dennoch alle wichtigen Features, die es für die Entwicklung mit Action-basierten Frameworks braucht. Zudem ist die Einstiegshürde, nicht zuletzt durch die strikte Verwendung bestehender EE-Standards, vergleichsweise gering.
Sven Kölpin ist Enterprise-Entwickler, Speaker und Autor bei der OPEN KNOWLEDGE GmbH in Oldenburg. Schwerpunkt und Leidenschaft ist die Konzeption und Entwicklung von Webanwendungen.
[1] Transferprozess: https://www.mvc-spec.org/news/2017/04/22/transfer-process-complete.html
[2] Status MVC: https://www.infoq.com/news/2018/01/mvc-1.0-public-review
[3] MVC-Spezifikation: https://oss.sonatype.org