Fancy stuff in Wicket 8: Models mit Lambda

Keine Kommentare

Wer in der Wicket-Community unterwegs ist, hat mitbekommen, dass es etwas länger gedauert hat, aber im Mai 2018 war es endlich soweit: Wicket 8 wurde released.

Klar, Wicket ist nicht mehr der „letzte Schrei“, ist aber schon lange ein stabiles und gut gewartetes Framework – Qualitäten, die in Webentwicklungsframeworks nicht immer selbstverständlich sind, und seit Wicket 6 ist auch die Dokumentation endlich so hilfreich, wie sie sein sollte. Außerdem bleiben wir von großen „Breaking Changes“ wie denen von Wicket 1.5 auf Wicket 6 verschont. Nicht zuletzt wegen dieser Stabilität wird Apache Wicket in Systemen mit höheren Sicherheitsanforderungen und klassischen Web-Frontends, wie zum Beispiel von Banken und Versicherungen, verwendet.

Wir werden in einer Reihe kurzer Blogartikel die wichtigsten Wicket-Features noch einmal kurz zeigen und die interessantesten Änderungen in Wicket 8 erklären. Zuerst widmen wir uns der Änderung, die zumindest auf unsere Projektarbeit den größten Einfluss hat: Models und wie die Arbeit mit ihnen durch Lambdas erleichtert wird:

Models allgemein

Erst einmal ein paar Worte zu Wicket im Allgemeinen: Apache Wicket ist ein auf Java aufsetzendes, komponentenbasiertes Webframework, in dem eine Pageklasse der Controller ist. Diese Page enthält einen Komponentenbaum, der aus Wicket-eigenen Komponenten, wie Links, Labels, Panels, Markupcontainer etc. bestehen kann, aber ebenso aus selbstgeschriebenen Komponenten.

Das Data-Binding in diesem Komponentenbaum wird mit sogenannten Models gemacht. Ein Model ist erstmal nur ein Interface, das zwei Methoden enthält:
getObject() und setObject(T data) zum Lesen und Schreiben der Daten.

Im einfachsten Fall ist ein Model also eine herumreichbare, schreibbare Objektreferenz. Durch diese Abstraktion können sich mehrere Komponenten dieselbe Datenquelle teilen, ohne sich untereinander zu kennen – Abhängigkeiten und mögliche Seiteneffekte werden reduziert. Durch Auslagerung dieser Logik in Models muss auch nicht jede Komponente von Hand geupdated werden, sondern die Komponenten selbst holen sich den aktuellen Stand aus ihrem Model.

HomePage.java:
IModel model = Model.of("Hello World!");
add(new Label("output1", model));
add(new Label("output2", model));
HomePage.html:
<span wicket:id="output1"></span>
<span wicket:id="output2"></span>

Hinter diesem schmalen Interface kann beliebige Logik abstrahiert werden, so dass die Daten auf jede beliebige Art und Weise beschafft und geschrieben werden können.
 

ResourceModel

Ein häufiger Anwendungsfall ist, auszugebende Strings nicht direkt im Code zu haben, sondern über Java Resource-Bundles zu laden, typischerweise aus .properties-Dateien. Hier hilft das ResourceModel. Diese Model-Implementierung übernimmt das Laden des Strings. Im Code wird nur das Model aus dem vorherigen Beispiel durch ein ResourceModel ersetzt.

IModel model = new ResourceModel("greeting");

 

PropertyModel

Was aber, wenn die Daten nicht über Ressourcen geliefert werden, sondern über Objekte, auf die wir eine Referenz haben? Hierfür gibt es das PropertyModel, das Attribute von Objekten mittels Reflection ausliest.

Greetable greetable = new Greetable();
IModel model = new PropertyModel<>(greetable, "greeting");
Greetable.java:
private String greeting;
 
public String getGreeting() {
            return greeting;
}

Das PropertyModel ist sehr komfortabel zu benutzen, aber nicht alle fühlen sich wohl damit, Reflection einzusetzen und dadurch ein Stück weit die durch Java gewährleistete Typsicherheit zu verlieren.
 

IModel

Stattdessen kann man ein IModel direkt implementieren. Hierfür müssen drei Methoden geschrieben werden, die weiter oben genannten setObject(T data) und getObject(), und detach(). detach() wird am Requestende aufgerufen, räumt gegebenenfalls auf und gibt Ressourcen frei. Für ein rein lesendes Model würden wir hier also zwei Methoden „leer“ lassen und nur getObject() implementieren.

        IModel<String> model = new IModel() {
            @Override
            public String getObject() {
                return greetable.getGreeting();
            }
 
            @Override
            public void setObject(String object) {
                // NOP
            }
 
            @Override
            public void detach() {
                // NOP
            }
        };

Das ist natürlich für den täglichen Gebrauch etwas unhandlich. Für diesen häufigen Fall gab es bisher das AbstractReadOnlyModel, das setObject und detach bereit stellt. Es muss also nur noch getObject implementiert werden:

IModel; model = new AbstractReadOnlyModel() {
            @Override
            public String getObject() {
                return greetable.getGreeting();
            }
        };

 

Read-only Models mit Lambdas

Mit dem auf Java 8 ausgerichteten Wicket 8 können wir diesen Anwendungsfall jetzt noch etwas einfacher umsetzen:

In Wicket 8 sind detach() und setObject() Default-Methoden geworden, müssen also nicht mehr implementiert werden. Das heißt, AbstractReadOnlyModels werden jetzt durch einfach IModels ersetzt, in denen nur die getObject Methode implementiert wird.

        IModel<String> model = new IModel() {
            @Override
            public String getObject() {
                return greetable.getGreeting();
            }
        };

 
Da es jetzt aber nur noch eine einzige abstrakte Methode gibt, können wir nach dem SAM (Single Abstract Method) Pattern einfach ein Lambda verwenden:

IModel<String> model = () -> greetable.getGreeting();

Fazit: Typsichere Read-Only Models sind mit Wicket 8 jetzt Einzeiler.
 

Übrigens: Wer in 4 Tagen so richtig viel über Apache Wicket lernen will – uns gibt es auch als Workshop, meldet euch bei Interesse einfach per Mail!

Antonia Schmalstieg

Vor nicht allzu langer Zeit hat Antonia sich aufgemacht, die Softwarewelt zu erobern – ihre Waffen der Wahl sind ihr agiler Werkzeugkoffer und ein Feuerzeug.
Sie liebt es, gute, elegante Lösungen zu anspruchsvollen Problemen zu finden.

Carl-Eric Menzel

Carl-Eric schreibt seit vielen Jahren Software, liest Code, und erklärt anderen, was er dabei gelernt hat.

Computer sind schrecklich, und es macht doch Spaß, den Maschinen zu sagen, was sie zu tun haben.

Weitere Inhalte zu Apache Wicket

Kommentieren

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.