Xtext 2.2 finally brings Maven support for Xtend

I cannot tell how often I was asked since introduction of Xtend2 how to compile them in a Maven build. This was just not possible until now due to the problem that to load and compile an Xtend class it is necessary to compile all of the Java classes that the Xtend class on before, and Java classes might depend on Xtend classes to be translated in order to be compilable.

Xtext 2.2.0 was just released yesterday, and for me the most important new feature is direct support through the xtend-maven-plugin plugin. I could not hesitate to test this feature, and created a small example.

Scenario

I have set up a small Maven project with 2 Java classes and 1 Xtend class that depend on each other.

To translate XtendClass1 to Java code and compile it requires that JavaClass1 is compiled before, and to compile JavaClass2 it is necessary that XtendClass is translated to Java code before.

Maven POM Configuration

I have decided to not use Maven Tycho for this example, and use the typical structure of an Eclipse project with usage of Xtend, i.e. sources in folder /src (instead /src/main/java) and xtend-gen to generate the Java code for Xtend classes to.

Repositories

Since shortly Xtext artifacts are available on maven.eclipse.org. The new Maven plugin is available on http://build.eclipse.org/common/xtend/maven/

	<repositories>
		<repository>
			<id>maven.eclipse.org</id>
			<url>http://maven.eclipse.org/nexus/content/groups/public/</url>
		</repository>
		<repository>
			<id>xtend</id>
			<url>http://build.eclipse.org/common/xtend/maven/</url>
		</repository>
	</repositories>
	<pluginRepositories>
		<pluginRepository>
			<id>xtend</id>
			<url>http://build.eclipse.org/common/xtend/maven/</url>
		</pluginRepository>
		<pluginRepository>
			<id>fornax</id>
			<url>http://fornax-platform.org/nexus/content/groups/public/</url>
		</pluginRepository>
	</pluginRepositories>

Dependencies

This small project setup requires just a mimimal set of dependencies to be configured:

	<dependencies>
		<dependency>
			<groupId>org.eclipse.xtend2</groupId>
			<artifactId>org.eclipse.xtend2.lib</artifactId>
			<version>2.2.0</version>
		</dependency>
		<dependency>
			<groupId>org.eclipse.xtext</groupId>
			<artifactId>org.eclipse.xtext.xtend2.lib</artifactId>
			<version>2.2.0.v201112061305</version>
		</dependency>
		<dependency>
			<groupId>com.google.inject</groupId>
			<artifactId>com.google.inject</artifactId>
			<version>2.0.0.v201105231817</version>
		</dependency>
	</dependencies>

Source folders

The main source folder src/ can be configured with the build/sourceDirectory setting, for xtend-gen we need the support of the build-helper-maven-plugin.

	<build>
		<sourceDirectory>src</sourceDirectory>
		<plugins>
			<plugin>
				<groupId>org.codehaus.mojo</groupId>
				<artifactId>build-helper-maven-plugin</artifactId>
				<version>1.7</version>
				<executions>
					<execution>
						<id>add-source</id>
						<phase>generate-sources</phase>
						<goals>
							<goal>add-source</goal>
						</goals>
						<configuration>
							<sources>
								<source>xtend-gen</source>
							</sources>
						</configuration>
					</execution>
				</executions>
			</plugin>
			...

The xtend-gen folder must be emptied when executing mvn clean, this requires some additional configuration of the maven-clean-plugin.

			<plugin>
				<artifactId>maven-clean-plugin</artifactId>
				<version>2.4.1</version>
				<configuration>
					<filesets>
						<fileset>
							<directory>xtend-gen</directory>
							<includes>
								<include>**</include>
							</includes>
						</fileset>
					</filesets>
				</configuration>
			</plugin>

xtend-maven-plugin

Now let’s finally come to the Xtend plugin. The plugin is configured as follows:

			<plugin>
				<groupId>org.eclipse.xtend2</groupId>
				<artifactId>xtend-maven-plugin</artifactId>
				<version>2.2.2</version>
				<executions>
					<execution>
						<goals>
							<goal>compile</goal>
							<goal>testCompile</goal>
						</goals>
						<configuration>
							<outputDirectory>xtend-gen</outputDirectory>
						</configuration>
					</execution>
				</executions>
			</plugin>

The outputDirectory is optional, but leaving it out the sources are generated to src/main/xtend-gen, and we want to generate to xtend-gen in the project root.

The plugin does not define a lifecycle mapping for M2E, which leads to an error marker “Plugin execution not covered by lifecycle configuration”. This is a well known issue when using M2E, and requires some additional work on the plugin. I have opened Bug#366118 for this.

Sample Project

The project described above is shared on Github: https://github.com/kthoms/xtext-experimental

In Eclipse the project looks like this after import (assuming the M2E plugin installed):

Build Execution

The classes in the project can now be built using mvn clean install. This will produce the following output:

[INFO] Scanning for projects...
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building xtend-maven-classic 2.2.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] --- maven-clean-plugin:2.4.1:clean (default-clean) @ xtend-maven-classic ---
[INFO] Deleting /Users/thoms/git/xtext-experimental/maven/xtend.maven/target
[INFO] Deleting /Users/thoms/git/xtext-experimental/maven/xtend.maven/xtend-gen (includes = [**], excludes = [])
[INFO] 
[INFO] --- build-helper-maven-plugin:1.7:add-source (add-source) @ xtend-maven-classic ---
[INFO] Source directory: /Users/thoms/git/xtext-experimental/maven/xtend.maven/xtend-gen added.
[INFO] 
[INFO] --- xtend-maven-plugin:2.2.0:compile (default) @ xtend-maven-classic ---
[WARNING] 
WARNING: 	XtendClass1.xtend - /Users/thoms/git/xtext-experimental/maven/xtend.maven/src/mypackage/XtendClass1.xtend
7: The value of the field XtendClass1.cls is not used
[INFO] Compiling 1 source file to xtend-gen
[INFO] 
[INFO] --- maven-resources-plugin:2.4.3:resources (default-resources) @ xtend-maven-classic ---
[WARNING] Using platform encoding (MacRoman actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory /Users/thoms/git/xtext-experimental/maven/xtend.maven/src/main/resources
[INFO] 
[INFO] --- maven-compiler-plugin:2.3.2:compile (default-compile) @ xtend-maven-classic ---
[WARNING] File encoding has not been set, using platform encoding MacRoman, i.e. build is platform dependent!
[INFO] Compiling 3 source files to /Users/thoms/git/xtext-experimental/maven/xtend.maven/target/classes
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 3.923s
[INFO] Finished at: Thu Dec 08 23:01:42 CET 2011
[INFO] Final Memory: 20M/81M
[INFO] ------------------------------------------------------------------------

From the output it can be seen that at the end 3 Java classes are compiled, after the xtend-maven-plugin created the Java code for the Xtend class.

Enabling debug output with -X reveals some more insight, how the plugin works:

[DEBUG] Configuring mojo 'org.eclipse.xtend2:xtend-maven-plugin:2.2.0:compile' with basic configurator -->
[DEBUG]   (f) outputDirectory = xtend-gen
[DEBUG]   (f) project = MavenProject: org.eclipse.xtext.example:xtend-maven-classic:2.2.0-SNAPSHOT @ /Users/thoms/git/xtext-experimental/maven/xtend.maven/pom.xml
[DEBUG]   (f) tempDirectory = /Users/thoms/git/xtext-experimental/maven/xtend.maven/target/xtend
[DEBUG] -- end configuration --
[DEBUG] load xtend file 'file:/Users/thoms/git/xtext-experimental/maven/xtend.maven/src/mypackage/XtendClass1.xtend'
[DEBUG] Parsing took: 42 ms
...
[DEBUG] create java stub 'mypackage/XtendClass1.java'
[DEBUG] invoke batch compiler with '-cp /Users/thoms/git/xtext-experimental/maven/xtend.maven/src:/Users/thoms/.m2/repository/org/eclipse/xtend2/org.eclipse.xtend2.lib/2.2.0/org.eclipse.xtend2.lib-2.2.0.jar:/Users/thoms/.m2/repository/com/google/guava/guava/10.0.1/guava-10.0.1.jar:/Users/thoms/.m2/repository/com/google/code/findbugs/jsr305/1.3.9/jsr305-1.3.9.jar:/Users/thoms/.m2/repository/org/eclipse/xtext/org.eclipse.xtext.xtend2.lib/2.2.0.v201112061305/org.eclipse.xtext.xtend2.lib-2.2.0.v201112061305.jar:/Users/thoms/.m2/repository/org/eclipse/xtext/org.eclipse.xtext.xbase.lib/2.2.0.v201112061305/org.eclipse.xtext.xbase.lib-2.2.0.v201112061305.jar:/Users/thoms/.m2/repository/com/google/inject/com.google.inject/2.0.0.v201105231817/com.google.inject-2.0.0.v201105231817.jar -d /Users/thoms/git/xtext-experimental/maven/xtend.maven/target/xtend/classes -1.5 -proceedOnError /Users/thoms/git/xtext-experimental/maven/xtend.maven/src /Users/thoms/git/xtext-experimental/maven/xtend.maven/target/xtend/stubs'
[DEBUG] classpath used for Xtend compilation : [file:/Users/thoms/git/xtext-experimental/maven/xtend.maven/src/, file:/Users/thoms/.m2/repository/org/eclipse/xtend2/org.eclipse.xtend2.lib/2.2.0/org.eclipse.xtend2.lib-2.2.0.jar, file:/Users/thoms/.m2/repository/com/google/guava/guava/10.0.1/guava-10.0.1.jar, file:/Users/thoms/.m2/repository/com/google/code/findbugs/jsr305/1.3.9/jsr305-1.3.9.jar, file:/Users/thoms/.m2/repository/org/eclipse/xtext/org.eclipse.xtext.xtend2.lib/2.2.0.v201112061305/org.eclipse.xtext.xtend2.lib-2.2.0.v201112061305.jar, file:/Users/thoms/.m2/repository/org/eclipse/xtext/org.eclipse.xtext.xbase.lib/2.2.0.v201112061305/org.eclipse.xtext.xbase.lib-2.2.0.v201112061305.jar, file:/Users/thoms/.m2/repository/com/google/inject/com.google.inject/2.0.0.v201105231817/com.google.inject-2.0.0.v201105231817.jar, file:/Users/thoms/git/xtext-experimental/maven/xtend.maven/src/, file:/Users/thoms/git/xtext-experimental/maven/xtend.maven/target/xtend/classes/]

The plugin invokes the Xtend Batch compiler through a spawned JVM. The batch compiler is realized in class org.eclipse.xtext.xtend2.compiler.batch.Xtend2BatchCompiler from the newly added plugin org.eclipse.xtext.xtend2.standalone.

After the build XtendClass1.java is generated as expected to xtend-gen. When opening the target folder it can be seen that the plugin produces a Java stub class to target/stubs for the Xtend class. Finally, everything is compiled and the project is clean 🙂

Limitation

The plugin only takes one source folder into account, namely the one configured by build/sourceDirectory. This is a problem when you have multiple source folders, which is quite typical for Xtext projects, namely src and src-gen. This is reported as , which is fixed in the meantime. I have deployed a patched version as unofficial release 2.2.2.

Conclusion

I deeply desired this plugin and this finally allows that the xtend-gen folder does not need to be checked in. The sample used here was just simple. Next would be a real life project were I want to apply the plugin, most likely in Project Spray. This project uses Xtend based code generation heavily and Maven Tycho for the build. The project has not been upgraded to Xtext 2.2.0 (of course, it was just released), and I guess we have to upgrade to Xtext 2.2.0 before we can use the plugin. But if this allows us to finally remove the xtend-gen folders from the repository this alone is worth upgrading.

Nice work, Xtext team!

19 thoughts on “Xtext 2.2 finally brings Maven support for Xtend

  1. Pingback: Xtend 2.2, linguagem variante do Java, está menos dependente do Eclipse | F2 - Sistemas

  2. Pingback: Xtend 2.2 Tidak Bergantung Pada Eclipse | LinuxBox.Web.ID

  3. Not working. The artifacts have pretty much disappeared from the Eclipse Nexus repository, so the dependencies don’t work. Also, this is fine and dandy for xtend, but what about xtext? Are there plans to allow for maven processing of mwe2 scripts without using the old fornax plugins?

  4. Denis,

    In the meantime Xtext 2.2.1 has been released, I am also not happy that artifacts just disappear. That’s not how I am used to work with Maven repositories.
    Anyway, this post is about compiling Xtend with Maven. Nothing more, nothing less. If the dependencies are not current anymore I think Maven users will be smart enough to replace the versions by recent ones. If someone wants to be indepedent from the Maven repository at Eclipse, then setting up a repository manager on own is the right approach. Executing MWE workflows is still and will be the responsibility of the Fornax workflow plugin.

    ~Karsten

  5. Hello,

    I also tested the Xtend Maven plugin with and without Eclipse and also have to state, that this was great work by the Xtext/Xtend team!

    I still have some problems and I don’t know if these are bugs or misuses of mine. Hopefully you can clear my mind.

    ————————————
    First problem
    ————————————

    Within Eclipse, I have the problem, that only one target folder is supported. Though, multiple source folders are supported, e.g. target/generated-sources/xtend and target/generated-sources/test-xtend, there is only one target folder in the Xtend Eclipse plugin configuration dialog. As a workaround it is possible to disable the Xtend compiler within Eclipse and invoke mvn generate-sources generate-test-sources. Does anybody has other suggestions?

    ————————————
    Second problem
    ————————————

    Outside of Eclipse, I got some encoding problems with UTF-8 on Windows. Not in normal Xtend code, but in JavaDoc-comments. It seems that the JavaDocs are not processed as UTF-8 (on Windows). If I have normal Xtend code, umlauts are processed correctly. But if I have the umlauts in JavaDoc e.g. /** @author Christian Gnüchtel */ on the command line the error message ‘unmappable character for encoding UTF-8’ appears and the build fails. (Within Eclipse all works fine and this problem does not occur. Also on a Linux system like Ubuntu – where UTF-8 is the system default – all works fine.)

    My encoding configuration in the pom.xml looks as following:


    <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    [...]

    <build>
    <plugins>
    <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-resources-plugin</artifactId>
    <version>2.4.3</version>
    <configuration>
    <encoding>${project.build.sourceEncoding}</encoding>
    </configuration>
    </plugin>
    <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>2.3.2</version>
    <configuration>
    <source>1.6</source>
    <target>1.6</target>
    <encoding>${project.build.sourceEncoding}</encoding>
    </configuration>
    </plugin>

    Are there more configuration tweaks?

    ————————————
    Third problem
    ————————————

    I am also confused which Maven dependencies should be used. (Maybe I am not one of these smart Maven users.) I am only using the following and it works for me (I am not using Xtext or Google-Inject dependencies right now, since I don’t know the current exact version):


    <dependencies>
    [...]
    <dependency>
    <groupId>org.eclipse.xtend2</groupId>
    <artifactId>org.eclipse.xtend2.lib</artifactId>
    <version>2.2.1</version>
    <scope>compile</scope>
    </dependency>
    <dependencies>

    <build>
    <plugins>
    <plugin>
    <groupId>org.eclipse.xtend2</groupId>
    <artifactId>xtend-maven-plugin</artifactId>
    <version>2.2.1</version>
    <executions>
    <execution>
    <goals>
    <goal>compile</goal>
    <goal>testCompile</goal>
    </goals>
    <configuration>
    <outputDirectory>${project.build.directory}/generated-sources/xtend</outputDirectory>
    <testOutputDirectory>${project.build.directory}/generated-sources/test-xtend</testOutputDirectory>
    </configuration>
    </execution>
    </executions>
    </plugin>
    [...]

    Is this set-up correctly or do I missing something?

    —–

    Can somebody help me please by reproducing the problems and/or answering my maybe simple questions?

    Christian

  6. (Thanks for deleting my misformatted comments! But my last comment was also deleted, so I post it again :-))

    For the second problem (UTF-8 encoding) there is also a simple workaround by using Unicode literals: @author Christian Gn\u00FCchtel.

  7. Hi Karsten,

    Have you tried to use the xtendstandalone compiler in ant build, it should also work for ant, not only for Maven, I don’t know if misuse it or make the wrong configuration, I always have errors, my ant target is like this:

    here, path “lib.path.id” already contains all the jar files include the xtend standalone compiler, but I always get the error:
    [java] 0 [main] INFO text.xtend2.resource.Xtend2Resource – Types can’t be null or empty []
    [java] java.lang.IllegalArgumentException: Types can’t be null or empty []
    [java] at org.eclipse.xtext.common.types.util.TypeConformanceComputer.getCommonSuperType(TypeConformanceComputer.java:190)
    [java] at org.eclipse.xtext.xtend2.resource.Xtend2Resource.commonType(Xtend2Resource.java:191)
    [java] at org.eclipse.xtext.xtend2.resource.Xtend2Resource.getEObject(Xtend2Resource.java:111)
    [java] at org.eclipse.emf.ecore.resource.impl.ResourceSetImpl.getEObject(ResourceSetImpl.java:219)
    [java] at org.eclipse.emf.ecore.util.EcoreUtil.resolve(EcoreUtil.java:203)
    [java] at org.eclipse.emf.ecore.util.EcoreUtil.resolve(EcoreUtil.java:263)…

    Anyone else have tried it with ant, succeed? Thanks

    • target name=”xtend-gen” description=”Generate xtend file to java files”
      path id=”classpath”>

      /path
      pathconvert property=”classpathline” refid=”classpath” pathsep=”${path.separator}”/
      java classname=”org.eclipse.xtext.xtend2.compiler.batch.Main” classpathref=”lib.path.id”
      arg value=”-d xtend-gen”/>
      arg value=”-cp ${classpathline} “/>
      arg value=”src”/>
      /java
      /target

      I delete some “<" to make it shown.

      • No, I haven’t tried it. I’m using Maven usually. Anyway, the plugin does not much more than you are doing in your ant script, so basically this would be the right approach.

  8. Good job, I, too, could finally stop committing generated files to SVN!

    However, I couldn’t find any channel where the status of the maven plugin is being announced, so I had to search for quite some time, whether and since when multiple source folders are supported. Tickets in bugzilla more often than not just say fixed without mentioning a version. The best hint I could find is hidden in this spray ticket: http://code.google.com/a/eclipselabs.org/p/spray/issues/detail?id=94

    For future development: where should I search for versions of these maven plugins and learn what’s new in each version?

  9. Hello, I wonder how I can validate xtext 2.2.1 when the name of a feature is repeated, as you can explore the structure, language check is done as follows:

    IndValor context ERROR “Duplicate Definition Index …!” :
    allElements (). typeSelect (IndValor). select (e | e.name ==
    this.name). size == 1;

    xtext 2.2.1 but I could not validate this part.

    Thanks for the reply

    • The check you are mentioning here is from Xpand’s check. In Xtext duplicate names are automatically validated through the NamesAreUniqueValidator, which is a composed validation by default. The IQualifiedNameProvider is the instance which has to compute names for elements. The validation is per resource, i.e. a duplicate name in another resource is not checked, therefore the IGlobalScopeProvider must be queried.

  10. Pingback: Unofficial release 2.2.2 of the Xtend Maven Plugin « Karsten's Blog

  11. Groovy’s tooling looks very good. There are just a few oddities but mainly I think it’s well done… in contrast to the Scala plugin (I used 2.0.0 RC4). It holds a lot of surprises. For instance, with the Scala-IDE installed you’ll get Scala-related template proposals in the Java and the Groovy editor. Still Scala the language would be my personal choice if I had to decide between the two. Anyway, this post is not about language features or Eclipse-plugin quality, but about what I experienced regarding runtime performance.

  12. I am getting the error during the xtext migration, please let me know what is the reason of the following error..
    I followed all following process for migrate the xtext version.
    1. Delete the old plug-ins and update the latest plug-ins in target platform.
    2. Update the Plug-in Dependencies and Import Statements.
    3. Introduction of the Qualified Name.
    4. Changes in the index and in find references.
    5. Rewritten Node Model.
    6. AutoEditStrategy.
    7. Other Noteworthy API Changes
    To consider the above steps, I started the work with Eclipse-4.2, Which has a xtext-2.3.0 dependency. Successfully I completed the all above steps and removed the compilation error.

    Problem: After that I start the testing and getting below error Messages:
    [XtextLinkingDiagnostic: null:6 Couldn’t resolve reference to Material ‘MPS_RECUR’.,
    XtextLinkingDiagnostic: null:9 Couldn’t resolve reference to Cstic ‘NUM_OF_ALLOC’.,
    XtextLinkingDiagnostic: null:15 Couldn’t resolve reference to Cstic ‘INSTANCE_NUM’.,
    XtextLinkingDiagnostic: null:14 Couldn’t resolve reference to Class ‘ALLOC’.]

Leave a comment