Showing posts with label Maven. Show all posts
Showing posts with label Maven. Show all posts

Thursday, October 7, 2010

More on Groovy-Eclipse and Maven

I've had a few requests for the source code for the Groovy-Eclipse integration for maven, as well as a sample project that uses it. You can get both the sample project and groovy-eclipse compiler plugin for maven.

They are packaged as two m2eclipse projects, and it is recommended (although not necessary) to import them into Eclipse to use them.

The groovy-eclipse-compiler project contains the compiler integration. It is a single Java class that calls into the Groovy-enhanced JDT compiler. This maven plugin uses plexus to hook into maven's compiler plugin.

The groovy-eclipse-maven-tests project is a very simple maven project that has a few Groovy and Java classes that interact with each other. If you want to create your own project using the Groovy-Eclipse maven integration, I would recommend starting with this sample project.

Please let me know if you have any problems.

Monday, September 6, 2010

Where are all my stubs?



Update: you must also include a pluginRepositories section. See below for XML snippet.



Update: See here for a sample project and the source code of the compiler integration.




The standard way of compiling joint Groovy-Java code outside of Eclipse has always been through the use of stubs:

  1. Generate Java stub files for the Groovy files
  2. Compile the Java files using the stubs to compile against
  3. Compile the Groovy files

Although this works reasonably well in many situations, there are some complications and problems with this approach, most of which have already been described recently in detail on the groovy-dev mailing list here and here, so I won't go into them in this post.

About a year ago, we introduced Groovy-Eclipse 2.0, which compiles Groovy code by plugging into the JDT compiler and does not need to generate stub files. And as Andy Clement describes, it is possible to run the compiler in batch mode on the command line.

And now, with a little bit of glue code required, I have released a snapshot of the compiler with both ant and maven integration. Although, this is still early work, I do hope that this approach will solve many of the problems that Groovy programmers are having with stub generation. I'll describe below how they both work.

Ant integration for Groovy-Eclipse


Ant integration for the batch compiler is fairly simple.

  1. Download the groovy-eclipse-batch-0.5.0.jar from its temporary location.
  2. Add this jar to your ~/.ant/lib directory.
  3. Once you have that, you need to set the build.compiler property to org.codehaus.groovy.eclipse.ant.GroovyCompilerAdapter.

This will cause ant's javac task to delegate the Groovy-Eclipse compiler for the actual compilation. This means that it is possible to pass any combination of Groovy and Java files to the compiler and most parameters applicable for javac are still available when using the compiler adapter.

A very simple script that uses the Groovy compiler adapter looks like this:

<target name="compile">
  <property name="build.compiler"
           value="org.codehaus.groovy.eclipse.ant.GroovyCompilerAdapter">
  <javac srcdir="src" destdir="bin"/>
</target>

This script sets compiler adapter and compiles all source files in src, placing the resulting class files in bin. Both *.java files and *.groovy files are included in the compilation.

Maven integration for Groovy-Eclipse


Groovy-Eclipse can now also be used from maven. To do so, add the following to your pom.xml.

The artifacts are currently in the SpringSource snapshot maven repo. You must add it as a regular repository:

<repositories>
  <repository>
  <id>springsource</id>
  <url>http://maven.springframework.org/snapshot</url>
  <releases><enabled>true</enabled></releases>
  <snapshots><enabled>true</enabled></snapshots>
  </repository>
</repositories>

as well as a plugin repository:

<pluginRepositories>
  <pluginRepository>
  <id>springsource</id>
  <url>http://maven.springframework.org/snapshot</url>
  </pluginRepository>
</pluginRepositories>

And in your plugin section, you must change the compiler used by the maven-compiler-plugin. Like the javac ant task, the maven-compiler-plugin does not actually compile, but rather delegates the compilation to a different artifact:

<build>
...
<plugins>
  <plugin>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>2.3.1</version>
    <configuration>
      <compilerId>groovy-eclipse-compiler</compilerId>
      <verbose>true</verbose>
    </configuration>
    <dependencies>
      <dependency>
        <groupId>org.codehaus.groovy</groupId>
        <artifactId>groovy-eclipse-compiler</artifactId>
        <version>0.0.1-SNAPSHOT</version>
      </dependency>
    </dependencies>
  </plugin>
  ...
</plugins>
</build>

This will allow Groovy files to be compiled. The maven-compiler-plugin prefers all source files to be in src/main/java and src/test/java, but if you prefer you can use the standard Groovy convention and keep your files in src/main/groovy and src/test/groovy. You can do so by adding the following plugin to your build section of the pom:

<plugin>
  <groupId>org.codehaus.mojo</groupId>
  <artifactId>build-helper-maven-plugin</artifactId>
  <version>1.5</version>
  <executions>
    <execution>
      <id>add-source</id>
      <phase>generate-sources</phase>
      <goals>
        <goal>add-source</goal>
      </goals>
      <configuration>
        <sources>
          src/main/groovy
          src/test/groovy
        </sources> 
      </configuration>
    </execution>
  </executions>
</plugin>

This approach is still in an alpha state and has not been widely tested. It was hard to find reasonably large Groovy-Java projects that use maven for me to try this on. The largest project I have compiled in this way is the GPars project (GPars uses gradle for its build, but I adapted its build.gradle to a pom.xml and successfully ran maven on it). This project includes 168 Java and Groovy files in main as well as 338 Groovy files in test. In a not particularly scientific manner, I did a few runs of building the main and test classes using both Groovy-Eclipse and GMaven and the results are that Groovy-Eclipse is reasonably faster than GMaven for this project:

  • Time to compile main and test classes using GMaven: 36s
  • Time to compile main and test classes using Groovy-Eclipse: 28s

In addition to being largely untested in the wild, there are a few caveats when using Groovy-Eclipse:

  • Since stubs are not generated, GroovyDoc and any other artifacts that rely on stubs cannot be generated.
  • This only supports Groovy 1.7.
  • Third (ant only), your project must have at least one Java file in it (this can be an empty stub), or else ant will finish without compiling anything. There is a patch for this (Bug 48829), but I am waiting for it to be contributed back to ant.
  • Fourth (maven only), your maven project must have at least one groovy file or else compilation will not occur. (Though, if your project doesn't have any Groovy files, then why are you using a Groovy compiler?)

There is still some work to be done, but it is ready enough for people to start trying it out. Feedback is greatly appreciated. You can reply to this blog post, send a message to the mailing list, or raise an issue on jira.

Monday, December 14, 2009

Getting GMaven to play nicely with Groovy-Eclipse

There has been a lot of talk on the Groovy mailing list lately about how to get GMaven working with Groovy-Eclipse and coincidentally I saw my friend Mike last night who works at boats.com and he told me that his office has solved this problem. Here is what he told me:



Okay, the first things you will need in your POM file are the GMaven mojo and the GMaven runtime. The dependencies for the mojo seem to be a big buggered out of the box, so you will have to tweak the GMaven runtime dependencies. Here is how you do it:


<dependencies>
<dependency>
<groupId>org.codehaus.groovy.maven</groupId>
<artifactId>gmaven-mojo</artifactId>
<version>1.0</version>
<exclusions>
<exclusion>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all-minimal</artifactId>
</exclusion>
<exclusion>
<groupId>org.codehaus.groovy.maven.runtime</groupId>
<artifactId>gmaven-runtime-1.5</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.codehaus.groovy.maven.runtime</groupId>
<artifactId>gmaven-runtime-1.6</artifactId>
<version>1.0</version>
</dependency>
</dependencies>


Next is your build configuration. Eclipse will need to be able to find your Groovy source files, so you will need to add your Groovy source as an explicit resource directory.

The mvn:eclipse plugin will also need to add the Groovy nature to your project.

You will also need to add directives for the GMaven plugin. This is where you will have to do a manual tweak: when using mvn to build your project, gmaven generates some stubs for your groovy code before the java code compiles, so that any java->groovy dependencies will be fulfilled. The Groovy code is then compiled and will overwrite the .class files from the previous step. This breaks things in eclipse, since if you attempt to execute code in your workbench, eclipse sees the stubs and somehow their .class files are what end up in your binary output directory.

Therefore, if you want to execute a gmaven project from Eclipse, you simply need to comment out the stub generation directive and delete any generated stub classes. This is what it looks like:


<build>
<resources>
<resource>
<directory>src/main/groovy</directory>
</resource>
</resources>
<plugins>
<plugin>
<artifactId>maven-eclipse-plugin</artifactId>
<configuration>
<additionalProjectnatures>
<projectnature>
org.eclipse.jdt.groovy.core.groovyNature
</projectnature>
</additionalProjectnatures>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.groovy.maven</groupId>
<artifactId>gmaven-plugin</artifactId>
<version>1.0</version>
<executions>
<execution>
<goals>
<!--
<goal>generateStubs</goal>
-->
<goal>compile</goal>
<!--
<goal>generateTestStubs</goal>
-->
<goal>testCompile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

The result is a groovy/java project that can be managed with maven but can be transparently developed (and more importantly, debugged!) in Eclipse.

There is one minor issue that has come up however: GMaven 1.6 stub generation is broken for enums: it generates public constructors, which do not compile. I submitted an issue to codehaus (GMAVEN-51), and apparently the workaround is to use the gmaven 1.7 runtime. I haven't tried it yet, since things are working okay for us thus far.

Mike


So, it does seem like there is a bit of a problem with stubs being recognized by Groovy-Eclipse when they should not be. The solution would be to generate the stubs in a directory that is not seen by Eclipse, rather than in the default output directory. But not knowing much about GMaven (or Maven for that matter) works, I don't know how feasible this is. Can anyone think of a better solution?