Codegenerierung mit Eclipse Xtend

Xtend – eine Sprache für Java-Entwickler

Sven Efftinge und Jan Köhnlein

Xtend [6] ist eine statisch getypte Programmiersprache, die speziell auf die Bedürfnisse von Java-Entwickler zugeschnitten ist. Sowohl die Sprache als auch die Eclipse Plug-ins integrieren sich nahtlos mit bestehenden Java-Projekten. Xtend wird bei Eclipse und auf Basis von Xtext 2.0 [1] entwickelt.

Ob in der Webentwicklung zur Generierung von HTML-Seiten oder unter dem Namen Scaffolding in Frameworks wie Spring Roo oder Grails: Codegenerierung finden wir heute in der einen oder anderen Form in den allermeisten Projekten. Aus gutem Grund, schließlich können mit dieser Technik gerade strukturelle Information sehr gut abstrahiert werden. Komplexe Codegeneratoren sind allerdings leider auch oft sehr schwer zu verstehen und zu warten. Weiterhin wirkt sich ein zusätzlicher Codegenerierungsschritt im Entwicklungsprozess immer etwas negativ auf die Turnaround-Zeiten aus. In diesem Artikel erfahren Sie, wie die Sprache Xtend diese Probleme adressiert, sodass die Entwicklung von Codegeneratoren richtig Spaß macht.

Ein Codegenerator ist ein Programm, das aus beliebigen gegebenen Informationen, die üblicherweise in Form eines getypten Objektbaums zur Verfügung stehen, Text erzeugt. Dabei ist der Name Codegenerator ein bisschen irreführend, da es dabei nicht unbedingt um Code im engeren Sinne gehen muss. Das Hauptproblem ist also die Erzeugung von Text aus einem Modell. Die leserlichste Form, einen Text mit dynamischen Werten zu erzeugen, ist die Verwendung einer so genannten Template-Syntax. Dabei werden innerhalb von mehrzeiligen String-Literalen Ausdrücke eingebettet. Viele dynamische Sprachen (z. B. Groovy) unterstützen eine solche Syntax ebenfalls. Leider bieten diese Sprachen keine statische Typisierung, die aber bei der Entwicklung von Codegeneratoren extrem wichtig ist. Beziehen sich die Templates auf ein Modell, das selbst wie auch der Codegenerator iterativ wächst und an veränderte Projektbedingungen angepasst werden muss, ist es ausgesprochen hilfreich, wenn die IDE dies bei der Entwicklung unterstützt. Statische Typisierung ist quasi die Bedingung für Refactorings, Fehlermeldungen zur Compile-Zeit und ausgefeilte Autovervollständigung. Xtend bietet dies und einige andere sehr nützliche Eigenschaften. Fangen wir am besten mit einem kleinen Beispiel an.

Mein erster Codegenerator

Wir wollen zunächst für gegebene Instanzen von java.lang.Class<? > jeweils eine entsprechende Klassendeklaration generieren. Das ist zwar nicht außerordentlich sinnvoll, reicht aber aus, um einen Eindruck von Xtend zu vermitteln.

class SimpleJavaBeansGenerator {
   def generateJavaCode(Class> clazz) '''
       package «clazz.getPackage().getName()»;
     
       public class «clazz.getName()» {
       }
   '''   
}

Als Erstes fällt auf, dass in Xtend, genau wie in Java, Klassen definiert werden. Tatsächlich müssen die Dateien auch in einem Java-Source-Ordner liegen. Innerhalb einer Klasse können nun Methoden deklariert werden. Der Rumpf der Methode generateJavaCode besteht aus einem einzigen Template-Ausdruck. Template-Ausdrücke sind vom Typ java.lang.CharSequence und werden in Xtend durch jeweils drei einfache Anführungszeichen begonnen und beendet. Dazwischen kann beliebiger Text stehen. Um innerhalb des statischen Texts nun dynamischen Text einzufügen, wird ein Tag eingeführt, das durch französische Anführungszeichen (« und ») begrenzt ist. Innerhalb dieser Tags können beliebige Ausdrücke stehen.

Xtend kompiliert gegen Java, ist statisch getypt und bietet volle Unterstützung für Java Generics. Die Syntax für Typsignaturen ist identisch mit der aus Java bekannten Schreibweise, was sicherstellt, dass beliebige existierende Java-Bibliotheken verwendet und erfahrene Java-Entwickler in sehr kurzer Zeit produktiv werden können. Im Gegensatz zu Java müssen Typen allerdings nur selten hingeschrieben werden, weil sie, wann immer möglich, aus dem Kontext inferiert werden (Typinferenz [2]).

Beim Speichern einer Datei wird diese automatisch im Hintergrund zu lesbarem Java-Code übersetzt, was zusätzlich hilft, die verschiedenen Sprachkonzepte zu verstehen. Außerdem ist es so möglich, die vielen Optimierungen im Java-Compiler wiederzuverwenden (Abb 1).

Abb. 1: Xtend und Java vis-à-visAbb. 1: Xtend und Java vis-à-vis (Vergrößern)

Die abgeleitete Xtend-Klasse kann nun wie jede andere Java-Klasse aufgerufen werden:

public static void main(String... args) {
  SimpleJavaBeansGenerator generator = new SimpleJavaBeansGenerator();
  System.out.println(generator.generateJavaCode(Object.class));
}

Wie zu erwarten war, wird beim Ausführen der mehrzeilige String auf die Console geschrieben. Gegenüber Java bietet Xtend an vielen Stellen eine erheblich kürzere und lesbarere Schreibweise: Statt der Getter-Methode kann z. B. der Name der Property, im Sinne der JavaBeans-Semantik, verwendet werden. Der Ausdruck clazz.name wird dann automatisch nach clazz.getName()übersetzt, wie man im generierten Java-Code leicht verifizieren kann. Auch können leere Klammern bei Methodenaufrufen einfach weggelassen werden.

Als Nächstes wollen wir für jedes Field von clazz ein entsprechendes Java-Feld generieren. Dazu benutzen wir die FOR-Schleife:

def generateJavaCode(Class> clazz) '''
       package «clazz.getPackage.name»;
       
       public class «clazz.name» {
           «FOR f : clazz.fields»
               private «f.type.name» «f.name»;
           «ENDFOR»
       }
'''

Dabei ist f der Bezeichner der Laufvariablen und clazz.fields deren Wertebereich. Der Schleifenkörper wird mit ENDFOR beendet.

Geschrieben von
Sven Efftinge und Jan Köhnlein
Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.