Projekt Lombok versteckt auf elegante Weise sogenannten Boilerplate-Code. Getter, Setter und all das, was Entwickler im Leben ungefähr 2 Millionen Mal per IDE generieren – all das soll mit Lombok wegfallen. Ist die Einstiegshürde erst einmal überwunden, funktioniert das wirklich.
Wer erinnert sich eigentlich noch an die vielen Java-Enterprise-Beans der Version 1 oder 2, die unsäglichen Schmerzen, die einem damals bei professioneller Entwicklung widerfahren sind und die große Erleichterung die schließlich mit POJOs kam. Plain-Old-Java-Objects: Endlich testbarer Code! Code, den man auch verstehen konnte. Es gab nur zwei Regeln die man akzeptieren musste:
- Alle Klassen müssen einen parameterlosen Konstruktor haben.
- Alle Felder müssen Getter und Setter haben.
Verglichen mit dem was die Entwicklergemeinschaft vorher hatte, war das kein Problem. Leider müssen noch die Methoden toString, equals und hashCode überschrieben werden. (Listing 1) zeigt eine einfache Klasse mit zwei Konstruktoren und den Boilerplate-Code, wie er üblicherweise erwartet wird. Glücklicherweise hilft jeder gängige Editor diesen Code per Shortcuts zu generieren. Will nicht jeder diese Art von Code so schnell wie möglich hinter sich bringen? Mittlerweile hat man sich allerdings daran gewöhnt.
Aber warum erzeugt man den gleichen Code immer und immer wieder und versioniert ihn in unseren Source-Repositories? Wie stellt man sicher, dass zum Beispiel equals neu generiert wird, wenn beispielsweise ein neues Feld hinzugefügt wird? Muss man eigentlich Boilerplate-Code testen, wenn man ihn mit der IDE generiert? Ist es sinnvoll, Code der immer wieder auf seine Art gleich ist, zu duplizieren? Jede Code-Zeile ist eine Entscheidung die man bewusst treffen sollte. Im Fall von get und set mangelt es aber an guten, durchsetzungsfähigen Lösungen. Warum nicht einfach alles public machen? Puristen würden vielleicht laut vor Entsetzen aufschreien, andere dagegen sogar frohlocken.
Mit Lombok kann Boilerplate-Code endgültig ins Reich der Dinosaurier verbannt werden und der moderne Entwickler kann sich nun auf das konzentrieren, was wirklich wichtig ist.
(Listing 1)
Lomboker werden
Lombok zu verwenden muss eine bewusste Entscheidung sein und im Team getroffen werden. Jeder Entwickler muss dafür ein Plugin für seine IDE installieren. Auf der Lombok-Webseite finden sich die Plugins zum Download, samt Installationsanleitung. Für manche Anwender stellt bereits das eine große Hürde da und leider ist das noch nicht alles. (Listing 2) zeigt die Abhängigkeit, die man benötigt, um die Lombok-Annotations in seinem Projekt verwenden zu können. Zudem zeigt(Listing 3), wie man Lombok via Maven in seine Compiler-Konfiguration einbindet, damit man auch außerhalb der IDE lauffähige Pakete erzeugen kann. Etwas Arbeit muss man also in seine Umgebung stecken, bevor es los gehen kann. Bei einem 50 Personenteam kann das also auch schon etwas dauern.
(Listing 2)
(Listing 3)
Nie mehr Getter und Setter
Wenn einmal alles aufgesetzt ist, kann die Category Klasse leicht neu geschrieben werden (Listing 4). Eine weitere Aktion ist nicht notwendig. Das Lombok-Plugin erzeugt im Hintergrund bereits Code für die Get- und Set-Methoden. Die IDE kann diese Methoden auch bereits ganz normal verwenden. Der Entwicklungsfluss ist also nicht gestört. Kein separates Kompilieren oder Knöpfchen klicken. Alles ist einfach da (Abb. 1).
(Listing 4)
Selbstverständlich gibt es auch Annotation für equals, hashCode und toString, nämlich @ToString und @EqualsAndHashCode. Wer gleich das volle Pauschalpaket möchte, verwendet nicht diese vier Annotations, sondern lediglich @Data, was alle vier Optionen beinhaltet (Listing 5).
(Listing 5)
Get und Set sind einfach da (Abb. 1)
Es ist außerdem möglich, die @Getter und @Setter Annotations über Felder zu schreiben, womit dann nur für diese Felder Getter und Setter generiert werden.
Wie man in die Glaskugel blickt
Lombok wird oft als Magie bezeichnet, was es irgendwie auch ist. Wer beispielsweise @Builder verwendet, wird feststellen, dass plötzlich eine gesamte API zum Bauen eines Objekts bereitgestellt wird. Übertragen auf das Category Beispiel, könnte also Code angewendet werden wie in (Listing 6).
(Listing 6)
Was geschieht da eigentlich? Wie kann man diese Lombok’sche Magie überhaupt verstehen? Und was, wenn das Team wieder weggehen möchte von Lombok? Auch das ist keine große Sache, denn dafür gibt es Delombok. Delombok ist verfügbar für einzelne Klassen über das IDE-Plugin und als Ant- oder Maven-Task, um gesamte Projekte aus der Lombok-Abhängigkeit zu befreien. Wer auf die Klasse von (Listing 6) rechts-klickt und (bei IntelliJ) mittels Refactoring die Option Delombok auswählt, wird feststellen, dass die Lombok-Annotations beseitigt werden. Stattdessen sieht man den Code, den Lombok generiert hat bzw. generieren würde. Im Falle der Builder-Annotation ist das der Code aus (Listing 7).
(Listing 7)
Weitere wichtige Annotations
Das Prinzip Lombok ist schnell erklärt und auch die Annotations sind schnell überblickt. Derzeit gibt es 17 stabile Features und mehrere experimentelle. Eines der wichtigsten Features ist @Log4j2. Es gibt diese Annotation auch für andere Logging-Frameworks. Lombok erzeugt dann einen Ready-to-use Logger für eine Klasse (Listing 8). Die meisten Entwickler haben sicher schon mehrmals eine Logger-Instanz erzeugt und dabei die falsche Klasse als Argument verwendet. Typische Fehler bei sich ständig wiederholendem Code sind oft auf Copy und Paste zurückzuführen.
(Listing 8)
Die Lombok-Annotation @Close ist ebenfalls sehr nützlich. Das korrekte Schließen eines InputStream wird mit @Close sehr einfach. Generiert wird Code, der im finally Block den InputStream schließt. Wer also (Listing 9) schreibt, erhält letzten Endes (Listing 10).
(Listing 9)
(Listing 10)
Zudem gibt es @val und @var. Damit ist es möglich, statt dem Referenz-Typen einfach var (Variable) oder val (final) anzugeben. Allerdings verliert man dann eine wichtige Information, die man möglicherweise zum zügigen Coden benötigt. Typen sind prinzipiell nicht schlecht. Ob jedoch alles was Lombok bietet auch verwendet werden sollte, bleibt dem Team überlassen. Weiter werden Immutability, Synchronized oder die automatische Generierung von Konstruktoren der verschiedensten Art unterstützt.
Fazit:
Ob Code-Generierung eine gut oder eher schlecht ist, muss jeder selbst für sich bzw. das Team entscheiden. Manche Entwickler meinen, dass auf diese einfache Art und Weise Getter und Setter zu generieren dazu verleiten würde, dass man nicht mehr über Datenkapselung nachdenkt und einfach prinzipiell alles via Get bzw. Set erreichbar macht. Es ist die Frage, ob Getter und Setter dann generell eine gute Idee sind. Ein Argument dagegen wäre, dass Entwickler die sich Getter und Setter von der IDE generieren lassen, das ja genauso gedankenlos machen können wie Entwickler die @Getter und @Setter schreiben. Die persönliche Erfahrung des Autors ist, dass der Code mit Lombok eleganter, kürzer und lesbarer geworden ist und die Einführung von Lombok problemlos war. Wer davon ausgeht, dass generierter Code generell besser und aktueller ist, der wird sich eher auf diese Magie einlassen als jemand der den gesamten Code sehen möchte.
Christian Grobmeier arbeitet selbst, ständig und gerne. Am liebsten mag er irgendwas mit Spring oder Solr. Er ist auch kein JavaScript-Kostverächter und treibt sich gerne mit Angular oder React rum. Hin und wieder greift er sogar zur Ruby und PhP Keule. Und wenn alles nichts mehr hilft, schreibt er ein Buch.
Webseite | Twitter | LinkedIn | GitHub | E-Mail