Skip to content

Technik Blog

Programmieren | Arduino | ESP32 | MicroPython | Python | Raspberry Pi | Raspberry Pi Pico

Menu
  • Smarthome
  • Arduino
  • ESP32 & Co.
  • Raspberry Pi & Pico
  • Solo Mining
  • Über mich
  • Deutsch
  • English
Menu

Java : mit „Projekt Lombok“ gegen Boilerplatecode

Posted on 25. September 20181. Mai 2023 by Stefan Draeger

Mit dem „Projekt Lombok“ kann man den Boilerplatecode seines Projektes auf ein Minimum reduzieren.

  • Aber was ist Boilerplatecode?
  • Wie richtet man Projekt Lombok ein?
    • Installieren des Plugins
    • Prüfen ob Projekt Lombok installiert wurde
  • Beispielprojekt
  • JUnit & Ecplise EclEmma Plugin
    • Projekt Lombok gegen Boilerplatecode
    • Konstruktor
    • Getter & Setter
    • Equals, hashCode & toString
    • Das Ergebnis & ein Fazit
    • Binäre Datei Greeting.class decompilieren
      • decompilierter Code

Aber was ist Boilerplatecode?

Boilerplatecode ist Quellcode welcher für die Verwendung von Klassen (und APIs) benötigt wird und nur ein geringes Abstraktionsniveau hat. D.h. es geht hier um Methoden wie Getter, Setter, Konstuktoren, equals, hascode und toString. Diese Methoden werden Bsp. Benötigt um POJOs, Entitys oder andere Objekte zu erzeugen, aber sonst haben diese keinen besonderen Mehrwert für die Anwendung.

Wie richtet man Projekt Lombok ein?

Um die Funktionen von Projekt Lombok (Im nachfolgenden nur noch als Lombok bezeichnet.) zu nutzen muss man ein Plugin installieren.

Dieses Plugin ist derzeit (stand 25.09.2018) leider nicht per Marketplace installierbar. 

Das Plugin muss somit von der Herstellerseite https://projectlombok.org/ heruntergeladen werden und kann danach mit einem doppelklick gestartet werden.

Das Plugin ist ein JavaArchiv, einige Browser werden beim Download eine Warnung anzeigen welche man Aktzeptieren muss.

Installieren des Plugins

Nachdem die Datei „lombok.jar“ mit einem doppelklick gestartet wurde, wird nach Eclipse Installationen gesucht.

Projekt Lombok - suchen nach Eclipse installationen
Projekt Lombok – suchen nach Eclipse installationen

Die Entwicklungsumgebung Eclipse kann als ZIP entpackt und in ein beliebiges Verzeichnis abgelegt werden, daher kann die Suche etwas länger dauern.

Wenn die Eclipse Installation nicht gefunden wurde, so kann diese mit der Schaltfläche „Specify location…“ hinzugefügt werden.
Im nächsten Schritt wird nun die Eclipse Installation durch das Setzen der Checkbox ausgewählt (1) (per default sind alle gewählt) und mit der Schaltfläche „Install / Update“ (2) wird die Installation gestartet.

Projekt Lombok - zusätzlich hinzugefügte Eclipse installation
Projekt Lombok – zusätzlich hinzugefügte Eclipse installation

Wurde das Plugin korrekt installiert, so wird der folgende Dialog angezeigt.

Projekt Lombok - installation des Plugins abgeschlossen
Projekt Lombok – installation des Plugins abgeschlossen

Wenn die Eclipse IDE mit eigenen Parametern für die virtuelle Maschine (-vm parameter) gestartet wird, so muss zusätzlich das JavaArchiv eingebunden werden. In diesem speziellen Fall wird die Zeile „-vmargs -javaagent:lombok.jar“ den Parametern angehängt.

Prüfen ob Projekt Lombok installiert wurde

Auch wenn die Installation des Frameworks „Projekt Lombok“ vermeldet, dass die Installation erfolgreich verlaufen ist, wollen wir prüfen, ob dieses wirklich so ist.
Dazu startet man Eclipse und öffnet über das Menü „Help“ > „About Eclipse IDE“ den Infodialog. Dort sollte es nun eine zusätzliche Zeile geben, wo auf das Plugin hingewiesen wird.

About Eclipse - validieren der Installation
About Eclipse – validieren der Installation

Beispielprojekt

Nehmen wir uns ein kleines einfaches Beispielprojekt „Greetings“.

public class Greeting {

	private String text;
	
	public Greeting(String text) {
		super();
		this.text = text;
	}

	public String getText() { return text; }

	public void setText(String text) { this.text = text; }

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((text == null) ? 0 : text.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Greeting other = (Greeting) obj;
		if (text == null) {
			if (other.text != null)
				return false;
		} else if (!text.equals(other.text))
			return false;
		return true;
	}

	@Override
	public String toString() { return "Greeting [text=" + text + "]"; }
}

In diesem Quellcode sieht man nun welchen Overhead man hat, wenn man nur eine kleine Klasse mit nur einem Text erzeugen möchte. Okay auf die Methoden equals, hashCode und toString kann verzichtet werden, jedoch ist es eine gängige Praxis diese Methoden zu implementieren.

In Eclipse lassen sich diese Methoden einfach über das Kontextmenü erzeugen und somit ist die „arbeit“ nur sehr gering. 

JUnit & Ecplise EclEmma Plugin

In jedem guten Java Projekt gibt es Testfälle für den Quellcode.

Hier nun ein kleiner JUnit Testfall für die Klasse „Greeting“

public class TestGreeting {

   private static Greeting greetingGerman;
   private static Greeting greetingEnglish;

   @BeforeAll
   static void beforeAllTestcases() {
     greetingGerman = new Greeting("Hallo Welt!");
     greetingEnglish = new Greeting("Hello World!");
   }

   @Test
   void testGreetingShouldBeNotNull() {
     assertNotNull(greetingGerman);
     assertNotNull(greetingEnglish);
   }

   @Test
   void testGreetingTextShouldBeNotEmpty() {
     assertFalse(isBlank(greetingGerman.getText()));
     assertFalse(isBlank(greetingEnglish.getText()));
   }

   private boolean isBlank(String text) { return text == null || text.trim().length() == 0; }
}

Führen wir die oben stehenden Testfälle einmal aus und nutzen zusätzlich das Testcoverage Plugin EclEmma zur Analyse.

Testcoverageanalyse mit Eclemma
Testcoverageanalyse mit Eclemma

Das Plugin zeigt nun an, das die Methoden equals, hashCode, toString sowie setText nicht getestet wurde und somit nur eine Testabdeckung von 39,2 % besteht. Um auf 100 % Testabdeckung zu kommen, muss man nun alle rot markierten Stellen mit einem JUnit Test abdecken. Und genau hier entstehen Aufwände, welche man sich sparen kann.

@Test
void testEquals() {
   Greeting g2 = new Greeting("Hallo Welt!");
   assertTrue(g2.equals(greetingGerman));

   assertTrue(g2.equals(g2));
   assertFalse(g2.equals(null));
   assertFalse(g2.equals(new Integer(1337)));
		
   Greeting g3 = new Greeting(null);
   assertFalse(g2.equals(g3));
   assertFalse(g3.equals(g2));
		
   Greeting g4 = new Greeting(null);
   assertTrue(g3.equals(g4));
}
	
@Test
void testSetText(){
   Greeting g4 = new Greeting("test");
   assertTrue(g4.getText().equalsIgnoreCase("test"));
		
   g4.setText("Hallo Welt!");
   assertTrue(g4.getText().equalsIgnoreCase("Hallo Welt!"));
}

@Test
void testHashCode() {
   Greeting g2 = new Greeting("Hallo Welt!");
   assertTrue(g2.hashCode() == greetingGerman.hashCode());
		
   Greeting g3 = new Greeting(null);
   assertFalse(g3.hashCode() == 0);
		
   Greeting g4 = new Greeting("test");
   assertTrue(g4.hashCode() == 3556529);		
}

@Test
void testToString() {
   Greeting g2 = new Greeting("Hallo Welt!");
   assertTrue(g2.toString().equalsIgnoreCase("Greeting [text=Hallo Welt!]"));
}

private boolean isBlank(String text) {
   return text == null || text.trim().length() == 0;
}

Wir haben es nun geschafft eine 100%ige Testabdeckung zu erstellen, okay das war jetzt bei der Klasse nicht die größte Herausforderung.

Projekt Lombok gegen Boilerplatecode

Nun wollen wir die Klasse „Greeting“ mit Annotations versehen, damit die unnötigen Methoden entfallen können. Dazu müssen wir dem Eclipseprojekt das JavaArchiv „lombok.jar“ hinzufügen. 

Im folgenden werde ich zeigen wie die Klasse „Greeting“ mit Hilfe von Lombok und Annotationen verkürzt werden kann.

Konstruktor

Widmen wir uns zuerst dem Konstruktor der Klasse, dieser nimmt den Wert für die Membervariable „Text“ entgegen.
Den Konstruktor können wir mit der Annotation „@RequiredArgsConstructor“ an der Klasse sowie der Annotation „@NonNull“ an der Membervariable „text“ ersetzen. Dieses wird uns auch angezeigt das dieser nun doppelt vorhanden ist.

Compilermeldung das die Methode doppelt vorhanden ist
Compilermeldung das die Methode doppelt vorhanden ist

Hier hat Lombok den Konstruktor bereits erzeugt nur das wir diesen nicht sehen können. Also entfernen wir den Konstrukur, man sieht in dem Tab „Outline“ das der Konstruktor trotzdem erhalten bleibt.

Getter & Setter

Als nächstes geht es dem Getter & Setter an den Kragen, diese werden mit der Annotation „@Getter“ & „@Setter“ überflüssig.
Der Annotation kann zusätzlich noch die Sichtbarkeit mitgegeben werden, d.h. soll der Getter bzw. Setter private, protected oder public sein. 

@NonNull
@Getter(value=AccessLevel.PRIVATE)
@Setter(value=AccessLevel.PROTECTED)
private String text;

Equals, hashCode & toString

Wie eingangs erwähnt, ist es gute Praxis die Methoden equals, hashCode und toString zu überschreiben. Dieses wird mit der Annotation „@EqualsAndHashCode“ & „@ToString“ an der Klasse erledigt. 

@EqualsAndHashCode
@ToString
public class Greeting {}

Das Ergebnis & ein Fazit

Haben wir nun alle Annotationen an der Klasse versehen, so sieht diese nun wie folgt aus:

package de.draegerit.greetings;

import lombok.AccessLevel;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.ToString;

@RequiredArgsConstructor
@EqualsAndHashCode
@ToString
public class Greeting {

   @NonNull
   @Getter(value=AccessLevel.PRIVATE)
   @Setter(value=AccessLevel.PROTECTED)
   private String text;
}

Und der Tab „Outline“ zeigt nun die Methoden, an welche wir durch die Annotationen ersetzt haben.

Eclipse - Tab "Outline"
Eclipse – Tab „Outline“

In dem Tab „Outline“ sieht man nun:

  • den Konstruktor,
  • die private Methode „getText();“,
  • die protected Methode „setText(String);“,

Des Weiteren sind die Methoden equals, hashCode und toString mit einem kleinen Dreieck nach oben versehen, das bedeutet, dass die Methode überschrieben wurden.

Jetzt könnten wir unseren JUnit Testfall ausdünnen und die Testfälle für equals, hashCode, toString und setText entfernen, aber weit gefehlt, denn diese Methoden existieren ja trotzdem noch. D.h. alles, was wir getan haben ist, die Methoden vor unseren Augen zu verstecken der Compiler sieht diese trotzdem noch. 

Die Testfälle für equals, hashCode und toString werden nun durch Lombok implementiert und dieses weicht von der Eclipse Version ab daher sind nun die Testfälle nicht mehr valide. Die toString Methode kann man sich ja noch auf der Konsole ausgeben aber beim Rest wird es dann doch schon etwas schwieriger. Hier hilft ein decompiler Plugin weiter.

Binäre Datei Greeting.class decompilieren

Für das decompilieren verwende ich das Eclipse Plugin „Enhanced Class Decompiler“ welches bequem über den Marketplace installiert werden kann.

Eclipse Plugin - Enhanced Class Decompiler
Eclipse Plugin – Enhanced Class Decompiler

decompilierter Code

Mit dem Plugin können wir uns nun den Quellcode anzeigen lassen und sieht die Implementierung von equals und hashCode.

package de.draegerit.greetings;

import lombok.NonNull;

public class Greeting {
	@NonNull
	private String text;

	@NonNull
	public String getText() {
		return this.text;
	}

	public void setText(@NonNull String text) {
		if (text == null) {
			throw new NullPointerException("text is marked @NonNull but is null");
		} else {
			this.text = text;
		}
	}

	public Greeting(@NonNull String text) {
		if (text == null) {
			throw new NullPointerException("text is marked @NonNull but is null");
		} else {
			this.text = text;
		}
	}

	public boolean equals(Object o) {
		if (o == this) {
			return true;
		} else if (!(o instanceof Greeting)) {
			return false;
		} else {
			Greeting other = (Greeting) o;
			if (!other.canEqual(this)) {
				return false;
			} else {
				Object this$text = this.getText();
				Object other$text = other.getText();
				if (this$text == null) {
					if (other$text != null) {
						return false;
					}
				} else if (!this$text.equals(other$text)) {
					return false;
				}

				return true;
			}
		}
	}

	protected boolean canEqual(Object other) {
		return other instanceof Greeting;
	}

	public int hashCode() {
		int PRIME = true;
		int result = 1;
		Object $text = this.getText();
		int result = result * 59 + ($text == null ? 43 : $text.hashCode());
		return result;
	}

	public String toString() {
		return "Greeting(text=" + this.getText() + ")";
	}
}

Schreibe einen Kommentar Antworten abbrechen

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

Fragen oder Feedback?

Du hast eine Idee, brauchst Hilfe oder möchtest Feedback loswerden?
Support-Ticket erstellen

Newsletter abonnieren

Bleib auf dem Laufenden: Erhalte regelmäßig Updates zu neuen Projekten, Tutorials und Tipps rund um Arduino, ESP32 und mehr – direkt in dein Postfach.

Jetzt Newsletter abonnieren

Unterstütze meinen Blog

Wenn dir meine Inhalte gefallen, freue ich mich über deine Unterstützung auf Tipeee.
So hilfst du mit, den Blog am Leben zu halten und neue Beiträge zu ermöglichen.

draeger-it.blog auf Tipeee unterstützen

Vielen Dank für deinen Support!
– Stefan Draeger

Kategorien

Tools

  • Unix-Zeitstempel-Rechner
  • ASCII Tabelle
  • Spannung, Strom, Widerstand und Leistung berechnen
  • Widerstandsrechner
  • 8×8 LED Matrix Tool
  • 8×16 LED Matrix Modul von Keyestudio
  • 16×16 LED Matrix – Generator

Links

Blogverzeichnis Bloggerei.de TopBlogs.de das Original - Blogverzeichnis | Blog Top Liste Blogverzeichnis trusted-blogs.com

Stefan Draeger
Königsberger Str. 13
38364 Schöningen

Tel.: 01778501273
E-Mail: info@draeger-it.blog

Folge mir auf

  • Impressum
  • Datenschutzerklärung
  • Disclaimer
  • Cookie-Richtlinie (EU)
©2025 Technik Blog | Built using WordPress and Responsive Blogily theme by Superb
Cookie-Zustimmung verwalten
Wir verwenden Technologien wie Cookies, um Geräteinformationen zu speichern und/oder darauf zuzugreifen. Wir tun dies, um das Surferlebnis zu verbessern und um personalisierte Werbung anzuzeigen. Wenn Sie diesen Technologien zustimmen, können wir Daten wie das Surfverhalten oder eindeutige IDs auf dieser Website verarbeiten. Wenn Sie Ihre Zustimmung nicht erteilen oder zurückziehen, können bestimmte Funktionen beeinträchtigt werden.
Funktional Immer aktiv
Die technische Speicherung oder der Zugang ist unbedingt erforderlich für den rechtmäßigen Zweck, die Nutzung eines bestimmten Dienstes zu ermöglichen, der vom Teilnehmer oder Nutzer ausdrücklich gewünscht wird, oder für den alleinigen Zweck, die Übertragung einer Nachricht über ein elektronisches Kommunikationsnetz durchzuführen.
Vorlieben
Die technische Speicherung oder der Zugriff ist für den rechtmäßigen Zweck der Speicherung von Präferenzen erforderlich, die nicht vom Abonnenten oder Benutzer angefordert wurden.
Statistiken
Die technische Speicherung oder der Zugriff, der ausschließlich zu statistischen Zwecken erfolgt. Die technische Speicherung oder der Zugriff, der ausschließlich zu anonymen statistischen Zwecken verwendet wird. Ohne eine Vorladung, die freiwillige Zustimmung deines Internetdienstanbieters oder zusätzliche Aufzeichnungen von Dritten können die zu diesem Zweck gespeicherten oder abgerufenen Informationen allein in der Regel nicht dazu verwendet werden, dich zu identifizieren.
Marketing
Die technische Speicherung oder der Zugriff ist erforderlich, um Nutzerprofile zu erstellen, um Werbung zu versenden oder um den Nutzer auf einer Website oder über mehrere Websites hinweg zu ähnlichen Marketingzwecken zu verfolgen.
Optionen verwalten Dienste verwalten Verwalten von {vendor_count}-Lieferanten Lese mehr über diese Zwecke
Einstellungen anzeigen
{title} {title} {title}