Das Anqu Method Plug-in für Eclipse

Named Querys – Umständlich war gestern

Mario Vöhl

(c) Shutterstock / Fabrik Bilder

Trotz eines viel gepriesenen Vorteils gegenüber den meisten anderen Persistenz-APIs führen Named Querys ein Schattendasein. Der Programmier-Overhead schreckt viele Entwickler ab. Doch Boilerplate Code kann ab jetzt keine Ausrede mehr sein!

Named Querys zur Abfrage von Datenbanken aus Java-Code gibt es schon lange: Querys, bei denen man Statements in einer SQL-artigen Sprache formuliert, die über Annotationen in Entity-Klassen registriert und später mit dem EntityManager erzeugt, konfiguriert und ausgeführt werden. Ein Beispiel einer vereinfachten User-Entity ist in Listing 1 zu sehen. Dort ist bereits eine parametrisierte Query zum Finden aller User mit einem zu übergebenden Namen annotiert.

NamedQueryAnUserEntity

Listing 1: @NamedQuery an der Beispiel-Entity

Listing 2 zeigt den Glue Code zum Ausführen der Query.

NamedQueryGlueCode

Listing 2: Glue Code für die Ausführung

Die Methode selbst ist hochgradig auf die Query spezialisiert und hat Rückgabewert und Parameter vom zu erwartenden Typ. Intern ruft der Code aber die generische EntityManager- und Query-API auf. Sie muss für alle erdenklichen Querys herhalten und ist daher beinahe untypisiert und String-basiert. Man beachte die Wiederholung von Strings („User.findByName“, „theName“) aus der Annotation.

Für jede Query wird immer wieder dieser Glue Code mit dem EntityManager benötigt. Es handelt sich also im wahrsten Sinne des Wortes um Boilerplate (engl. für Standardklausel, Textbaustein). Das ist sicherlich auch mit ein Grund, warum Alternativen wie die Criteria API, QueryDSL oder Spring Data JPA entstanden sind. Die allermeisten Ansätze führen jedoch zu dynamischen, also zur Laufzeit konstruierten, Abfragen.

Als goldene Regel findet man allerdings häufig die Empfehlung [1], für eine bessere Performance möglichst auf dynamische Querys zu verzichten. Landet man also zwangsläufig wieder bei statischen JPA Named Querys und dem erwähnten Glue Code?

Nein! Mit dem in diesem Artikel vorgestellten Tooling kann man sowohl schnell programmieren als auch performante Anwendungen erstellen.

Das Anqu Method Pattern

Das Anqu Method Pattern hat zum Ziel, die Nachteile von Named Querys zu minimieren und ihre Vorteile zu erhalten. Es stellt eine Empfehlung zur Programmierung von Named Querys dar und ist daher unabhängig von der verwendeten IDE zu sehen. Die drei Forderungen des Anqu Method Patterns sind:

  1. Einmaliger Glue Code in einer Methode: Der Glue Code für eine Named Query sollte genau einmal vorhanden sein. Er sollte sich in einer typisierten Methode befinden, deren einzige Aufgabe es ist, die Query auszuführen.
  2. Tiefer Glue Code: Die Methode mit dem Glue Code sollte sich in einer möglichst tiefen Schicht der Anwendung befinden. Es sollte eine Regel geben, wo man den Glue Code findet.
  3. Die Kopplungen testen: Die Code-Bestandteile, die zur Implementierung der Query beitragen, sind über Strings oder Reflection-Mechanismen gekoppelt. Diese Kopplungen sollten automatisiert getestet werden.

Das Anqu Method Plug-in

Das Anqu Method Plug-in für Eclipse unterstützt den Workflow zur Implementierung einer Named Query in allen drei Punkten. Anqu Method wird generell über das Kontextmenü aufgerufen. Wenn sich eine Aktion auf eine bestimmte Query bezieht, muss der Cursor dafür in der Query-Annotation stehen.

ContextMenue

Kontextmenü des Plug-ins

 

Am Beispiel der User-Entity kann der Ablauf etwa so aussehen:

Schritt 1: Über den Menüpunkt Anqu Method → New Named Query die benötigte Annotation generieren. Damit wird auch der Query-Name aus der umgebenden Entity vorbelegt.

Schritt 2: Ergänzung des Namens zu „User.findByName“.

Schritt 3: In einfachen Fällen wie „findByName“ ist schon ableitbar, was die Query liefern soll. Über den Menüpunkt  Anqu Method → Derive Statement wird dann die Abfrage direkt in der Annotation ergänzt. Das Ableiten des Statements funktioniert auch in komplexeren Fällen. Ansonsten besteht dieser Schritt darin, das Statement selbst zu verfassen.

Schritt 4: Erzeugung des Glue Codes. Hier sind zwei Entscheidungen zu treffen:

  • Welche Art der Ausführung wird benötigt? Bei schreibendem Zugriff (update, delete) oder Lesezugriff (select) mit mehreren Ergebnissen sollte der Menüpunkt Anqu Method → Execution gewählt werden. Wird nur maximal ein Ergebnis oder das erste Ergebnis eines Selects benötigt, sollte  Anqu Method → Single Result Execution verwendet werden.
  • Wohin soll der Code erzeugt werden? Je nach eigener Interpretation des Anqu Method Patterns soll die generierte Methode z.B. in einer DAO-Schicht oder frühestmöglich direkt in der Entity-Klasse platziert werden. Wenn das Ziel die Entity-Klasse ist, ist  → Method to Source zu wählen. Ansonsten geht der Umweg per → Method to Clipboard über die Zwischenablage. Entsprechend muss der Code am Zielort dann noch eingefügt werden.

Schritt 5: Über  Anqu Method → … → Tests as Configured ist es außerdem möglich, JUnit-Tests für die ausgewählte Query zu erzeugen. Je nach Einstellungen in den Preferences ist das Ziel der Generierung entweder eine neue Testklasse im Workspace oder die Zwischenablage.

Die Einstellungen zum Plug-in sind über  Anqu Method → Open Preferences erreichbar. Hier sollte man einmalig die eigene Interpretation des Anqu Method Patterns konfigurieren. Das wäre dann Schritt 0. Für Entwickler, die hauptsächlich an der Persistenzschicht arbeiten, lohnt es sich vielleicht auch, ein paar Tastenkürzel zu definieren. Dazu am besten in den allgemeinen Preferences →  General → Keys im Filterfeld anqu eingeben, um die relevanten Aktionen zu finden.

In diesem einfachen Fall wurde allein der Name der Query „findByName“ getippt. Der Rest war so offensichtlich, dass er generiert werden konnte.

Glue Code in der Entity?

Den Anstoß für das Plug-in gab ein etwas ausgeartetes Pattern für die Implementierung von Named Querys. Es basierte auf jeder Menge öffentlicher Stringkonstanten für den Query-Namen und für alle Parameter. Denn der Verwender der Query sollte ja nicht alles nochmal tippen müssen. Damit die Parameter-Konstanten auch an beiden Stellen verwendet wurden, musste das an sich gut lesbare Statement selbst in eine Konkatenation aus Text und Konstanten aufgebrochen werden. Letztendlich wurden die Konstanten dann auch noch für andere Querys wiederverwendet. So waren sonst unabhängige Statements plötzlich gekoppelt.

Da Stringkonstanten (public static final) bereits zur Compilezeit aufgelöst werden, wähnt man sich bei einem Refactoring fälschlicherweise vielleicht sogar noch in Sicherheit. Zudem muss der Verwender der Query immer noch selbst darauf achten, alle Parameter zu setzen.

Als radikale Antwort darauf entstand ein Plug-in, das den Glue Code in der Entity-Klasse „versteckt“. Wenn kein Programmierer jemals die Konstanten verwendet, müssen die Werte auch nicht ausgelagert werden. Die Methode ist statisch, getypt und vergisst keinen Parameter. Man mag für oder gegen Logik in Entity-Klassen sein. Doch besticht diese tiefstmögliche Glue-Code-Positionierung durch ihre Einfachheit, die durch die Kapselung und Zentralisierung des gesamten Codes in einer Klasse gegeben ist. Außerdem bietet sie ein hohes Maß an Wiederverwendbarkeit, denn der EntityManager ist hier ein Parameter der Methode.

SignaturTieferGlueCode

Listing 3: Signatur der Glue Code Methode in der Entity-Klasse

 

Zudem lassen sich die Schritte der Glue-Code-Generierung und der Test-Generierung mit diesem Muster zu einem einzigen Schritt zusammenfassen:  Anqu Method → … → Method to Source + Tests as Configured.

Teste die Kopplung!

Die generierten Tests bieten eine Art Schreibschutz für den Code, der mit der Query zusammen hängt. Dies betrifft Teile der Entity-Klasse, die Query-Annotation sowie den Glue Code. Wird also ein relevantes Feld der Entity umbenannt, schlägt ein Test fehl. Wird das Statement geändert, schlägt ebenfalls ein Test fehl. Und auch wenn der Glue Code geändert wird, schlägt ein Test fehl. Die Tests versuchen damit, das Verhalten eines Compilers nachzubilden. Sie basieren auf dem Framework Mockito, welches daher vorhanden sein muss.

Einer der Tests führt eine Prüfung aller im Statement enthaltenen Referenzen auf Klassen und Felder durch. Ein Tippfehler in einem Feldnamen, etwa „u.nam“ statt „u.name“, führt daher zu einem Testfehler. Die Tests können somit bereits bei der Erstellung der Query helfen.

Die Query selbst wird von den Tests nicht ausgeführt. Erfolgreich laufende Tests dieser Art machen also keine verlässliche Aussage darüber, ob die Abfrage zur Laufzeit in dem dann aktuellen Kontext (Deployment, Persistence Unit) funktioniert.

Query Mocking leicht gemacht

Wer seine Klassen isoliert mit JUnit testet, mockt gerne auch mal den EntityManager. Das Mocken einer @NamedQuery-Abfrage ist allerdings umständlich. Mit Anqu Method kann daher zu jeder Query eine MockUtility-Klasse erzeugt werden. Sie bietet statische Methoden, mit denen das Mock-Verhalten auf einfache Weise definiert werden kann.

Ist das noch Boilerplate?

Gedanklich wird Boilerplate oft mit Programmier-Overhead, mit langweiligen Aufgaben, gleichgesetzt. Wenn der benötigte Code aber immer gleichartig generiert werden kann, gibt es dann überhaupt noch ein Problem?

Wie im Beispiel-Ablauf gezeigt, muss in vielen Fällen für eine Query allein der Name eingegeben werden. Den Rest kann man mit wenigen Aufrufen des Plug-ins erledigen. Jeder möge dies mit dem eigenen Workflow zur Implementierung von Querys vergleichen.

Das Plug-in kann von www.anqu-method.de kostenlos geladen und verwendet werden. Es bietet noch weitere Features wie Pagination-Unterstützung oder auch Support für Spring Data JPA. Damit gibt es kaum noch einen Grund, großflächig Frameworks für dynamische Querys einzusetzen, wenn die Dynamik nicht zwingend notwendig ist.

Aufmacherbild: QUERY word concept von Shutterstock / Urheberrecht: Fabrik Bilder 

Verwandte Themen:

Geschrieben von
Mario Vöhl
Mario Vöhl
Mario Vöhl ist Diplom-Informatiker und arbeitet als Softwareentwickler und -architekt beim Verlag für Standesamtswesen in Frankfurt am Main. Er ist Entwickler des Anqu Method Plug-ins für Eclipse.
Kommentare

Hinterlasse einen Kommentar

4 Kommentare auf "Named Querys – Umständlich war gestern"

avatar
400
  Subscribe  
Benachrichtige mich zu:
Oliver Gierke
Gast

Das ist eigentlich ein gelöstes Problem, auf das man nicht mit Codegenerierung schlagen muss, siehe [0].

[0] http://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods.named-queries

Mario Vöhl
Gast

@Oliver Gierke:
Zum Glück hat Anqu die Antwort auf diesen Kommentar bereits eingebaut (siehe Screenshot in diesem Artikel). Ohne weitere IDE-Unterstützung muss bei Spring Data JPA für das Interface weiterhin Glue Code geschrieben werden, welcher mit Anqu erzeugt werden kann.
Wer Spring sowieso verwendet, kann die Zusatzfunktionen von Anqu benutzen, um die Query erstmal anzulegen und ggf. zu testen oder zu mocken.

Oliver Gierke
Gast
Kannst du da etwas konkreter werden? Welcher Gluecode muss den geschrieben werden? Im einfachsten Fall, deklarierst die Methode und bist fertig. Brauchst du einen komplexeren Query, annotierst du den an die Methode. Mir leuchtet nicht ganz ein, warum ich dafür zwingend ein IDE Plugin benötige. Code-Completion ist fein, aber eben nicht zwingend notwendig. Mir ist ebenfalls nicht ganz klar, was du mit Dynamischen Queries meinst. Queries, die aus Spring Data Methoden abgeleitet werden, werden beim Applikationsstart als CriteriaQuery’s erzeugt, gecacht und zur Laufzeit einfach in JPA Query Instanzen übersetzt und bekommen Parameter gebunden. Dass letzterer Schritt notwendig ist, ist von… Read more »