Wednesday, February 3, 2010

Groovy/java/maven: ultra short coding cycles, not

The whole Java (maven, groovy, gradle, ...) experience starts pissing me off more and more. I want to write code with ultra short compile/test cycles.




I've been working with python a bit last year. I had a pretty nice albeit crude development environment. Editor: gedit. No completion, no refactoring, nada. Together with nosyd I had 3-5 seconds feedback cycle between end of coding and test results. Great.

For various reasons, I am doing something similar with groovy now. Build time on the command line: 15-25 seconds (e.g. with gradle). This is too long. I've been spoiled. So ok. I've set up a full editor to speed up the build. I'll try avoiding firing it many times a day. I am back to around 5-8 seconds cycles (if the code was freshly compiled, 40 otherwise....). I can manage that... I have to, right ?

Then I need to add a dependency and the nightmare starts again.
Gradle dependencies aren't managed by intellij. So I think, I give up gradle and back to maven2. At least I know. Enters gmaven, the Groovy maven build environment. And after mucking around I find out that the latest gmaven dependencies aren't available in the official repo. (*) and I need them otherwise I hit this bug.

So I am spending time with the editor, the build system instead of writing code. My code runs 2-3 times slower than with python (it does things differently though). My development cycles are too long.

My productivity has halved (if not more). Makes me wonder if I should go back to python.

Morning argggggggggggggggggg !!!!!!!


update: OK Tim, you were right, the solution was in the bug, except that:

  1. the gmaven project has changed groupId. Perhaps obvious to someone following gmaven, but not to me when reading the issue
  2. the change wasn't sufficient, once I finally used the proper groupId, I ended up with this:

    [INFO] Unexpected node: Node[3:1,64,ANNOTATIONS]

    [INFO] ------------------------------------------------------------------------
    [INFO] Trace
    org.apache.maven.lifecycle.LifecycleExecutionException: Unexpected node: Node[3:1,64,ANNOTATIONS]
    at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoals(DefaultLifecycleExecutor.java:719)
    at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoalWithLifecycle(DefaultLifecycleExecutor.java:556)
    at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoal(DefaultLifecycleExecutor.java:535)
    at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoalAndHandleFailures(DefaultLifecycleExecutor.java:387)
    at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeTaskSegments(DefaultLifecycleExecutor.java:348)
    at org.apache.maven.lifecycle.DefaultLifecycleExecutor.execute(DefaultLifecycleExecutor.java:180)
    at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:328)
    at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:138)
    at org.apache.maven.cli.MavenCli.main(MavenCli.java:362)
    at org.apache.maven.cli.compat.CompatibleMain.main(CompatibleMain.java:60)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.codehaus.classworlds.Launcher.launchEnhanced(Launcher.java:315)
    at org.codehaus.classworlds.Launcher.launch(Launcher.java:255)
    at org.codehaus.classworlds.Launcher.mainWithExitCode(Launcher.java:430)
    at org.codehaus.classworlds.Launcher.main(Launcher.java:375)
    Caused by: org.apache.maven.plugin.MojoExecutionException: Unexpected node: Node[3:1,64,ANNOTATIONS]
    at org.codehaus.gmaven.plugin.MojoSupport.execute(MojoSupport.java:85)
    at org.codehaus.gmaven.plugin.stubgen.AbstractGenerateStubsMojo.execute(AbstractGenerateStubsMojo.java:60)
    at org.apache.maven.plugin.DefaultPluginManager.executeMojo(DefaultPluginManager.java:490)
    at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoals(DefaultLifecycleExecutor.java:694)
    ... 17 more
    Caused by: org.codehaus.gmaven.runtime.support.stubgen.UnexpectedNodeException: Unexpected node: Node[3:1,64,ANNOTATIONS]
    at org.codehaus.gmaven.runtime.support.stubgen.parser.NodeSupport.ensure(NodeSupport.java:96)
    at org.codehaus.gmaven.runtime.support.stubgen.model.ModelFactorySupport.identifier(ModelFactorySupport.java:896)
    at org.codehaus.gmaven.runtime.support.stubgen.model.ModelFactorySupport.importDef(ModelFactorySupport.java:185)
    at org.codehaus.gmaven.runtime.support.stubgen.model.ModelFactorySupport.process(ModelFactorySupport.java:122)
    at org.codehaus.gmaven.runtime.support.stubgen.model.ModelFactorySupport.create(ModelFactorySupport.java:90)
    at org.codehaus.gmaven.runtime.support.stubgen.model.ModelFactorySupport.create(ModelFactorySupport.java:61)
    at org.codehaus.gmaven.runtime.v1_6.StubCompilerFeature$StubCompilerImpl.render(StubCompilerFeature.java:101)
    at org.codehaus.gmaven.runtime.v1_6.StubCompilerFeature$StubCompilerImpl.compile(StubCompilerFeature.java:90)
    at org.codehaus.gmaven.plugin.stubgen.AbstractGenerateStubsMojo.compile(AbstractGenerateStubsMojo.java:160)
    at org.codehaus.gmaven.plugin.stubgen.AbstractGenerateStubsMojo.process(AbstractGenerateStubsMojo.java:131)
    at org.codehaus.gmaven.plugin.ComponentMojoSupport.doExecute(ComponentMojoSupport.java:60)
    at org.codehaus.gmaven.plugin.MojoSupport.execute(MojoSupport.java:69)
    ... 20 more
    [INFO] ------------------------------------------------------------------------


  3. this was more or less solved by using the POM extract referenced here,

    <dependencies>
    <dependency>
    <groupId>org.codehaus.groovy</groupId>
    <artifactId>groovy-all</artifactId>
    <version>1.7.0</version>
    </dependency>
    <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.7</version>
    <scope>test</scope>
    </dependency>
    </dependencies>

    <build>
    <plugins>
    <plugin>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>2.0.2</version>
    <configuration>
    <encoding>UTF-8</encoding>
    <source>1.5</source>
    <target>1.5</target>
    </configuration>
    </plugin>
    <plugin>
    <groupId>org.codehaus.gmaven</groupId>
    <artifactId>gmaven-plugin</artifactId>
    <version>1.2</version>
    <configuration>
    <providerSelection>1.7</providerSelection>
    </configuration>
    <executions>
    <execution>
    <goals>
    <goal>generateStubs</goal>
    <goal>compile</goal>
    <goal>generateTestStubs</goal>
    <goal>testCompile</goal>
    </goals>
    </execution>
    </executions>
    <!--dependencies>
    <dependency>
    <groupId>org.codehaus.groovy</groupId>
    <artifactId>groovy-all</artifactId>
    <version>1.7.0</version>
    </dependency>
    <dependency>
    <groupId>org.codehaus.gmaven.runtime</groupId>
    <artifactId>gmaven-runtime-1.7</artifactId>
    <version>1.2</version>
    <exclusions>
    <exclusion>
    <groupId>org.codehaus.groovy</groupId>
    <artifactId>groovy-all</artifactId>
    </exclusion>
    </exclusions>
    </dependency>
    </dependencies-->
    </plugin>
    </plugins>
    </build>


    until I hit:


    [INFO] ------------------------------------------------------------------------
    [INFO] Trace
    org.apache.maven.BuildFailureException: Compilation failure
    myorihect/target/generated-sources/groovy-stubs/main/genesis/GenesisException.java:[15,0] reference to RuntimeException is ambiguous, both method RuntimeException(java.lang.String) in java.lang.RuntimeException and method RuntimeException(java.lang.Throwable) in java.lang.RuntimeException match


    at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoals(DefaultLifecycleExecutor.java:715)
    at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoalWithLifecycle(DefaultLifecycleExecutor.java:556)
    at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoal(DefaultLifecycleExecutor.java:535)
    at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoalAndHandleFailures(DefaultLifecycleExecutor.java:387)
    at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeTaskSegments(DefaultLifecycleExecutor.java:348)
    at org.apache.maven.lifecycle.DefaultLifecycleExecutor.execute(DefaultLifecycleExecutor.java:180)
    at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:328)
    at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:138)
    at org.apache.maven.cli.MavenCli.main(MavenCli.java:362)
    at org.apache.maven.cli.compat.CompatibleMain.main(CompatibleMain.java:60)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.codehaus.classworlds.Launcher.launchEnhanced(Launcher.java:315)
    at org.codehaus.classworlds.Launcher.launch(Launcher.java:255)
    at org.codehaus.classworlds.Launcher.mainWithExitCode(Launcher.java:430)
    at org.codehaus.classworlds.Launcher.main(Launcher.java:375)
    Caused by: org.apache.maven.plugin.CompilationFailureException: Compilation failure
    myProject/target/generated-sources/groovy-stubs/main/genesis/GenesisException.java:[15,0] reference to RuntimeException is ambiguous, both method RuntimeException(java.lang.String) in java.lang.RuntimeException and method RuntimeException(java.lang.Throwable) in java.lang.RuntimeException match


    at org.apache.maven.plugin.AbstractCompilerMojo.execute(AbstractCompilerMojo.java:516)
    at org.apache.maven.plugin.CompilerMojo.execute(CompilerMojo.java:114)
    at org.apache.maven.plugin.DefaultPluginManager.executeMojo(DefaultPluginManager.java:490)
    at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoals(DefaultLifecycleExecutor.java:694)
    ... 17 more
    [INFO] ------------------------------------------------------------------------
    [INFO] Total time: 9 seconds
    [INFO] Finished at: Thu Feb 04 14:05:14 CET 2010
    [INFO] Final Memory: 21M/77M
    [INFO] ------------------------------------------------------------------------


    The culprit? an innocent project exception:

    class GenesisException extends RuntimeException {
    GenesisException(s) { super(s) }
    }


    Which I've changed to:


    class GenesisException extends RuntimeException {}


    to please someone in the stack tool.


Note that this code compiled properly without changes in intellij as well as with gradle and the following lines

usePlugin 'groovy'
repositories {
mavenCentral()
}

dependencies {
groovy 'org.codehaus.groovy:groovy:1.7.0'
testCompile 'junit:junit:4.7' // latest not yet available. see http://github.com/KentBeck/junit/issues/issue/66
}


A bit simpler isn't it ?



To take a bit of perspective I initially started this because intellij doesn't support fully gradle and that I had to manualy handle the dependencies in both gradle and intellij. I don't like that. Hence maven. I don't really want to use maven on that project, I just wanted to sync Intellij and the command line build dependencies easily.

So was this worth it ? How many features/bug fixes would I have implemented in the mean time using my 5 seconds compile/test feedback cycle ? Mmm. Better not to think about it.

4 comments:

  1. This comment has been removed by the author.

    ReplyDelete
  2. Wait, Jason Dillon provides you with a solution to the gmaven bug in the comments of the bug. Use the Groovy 1.7 runtime.

    What more could you ask for? You found a bug, and the bug has a solution in it.

    ReplyDelete
  3. Right, so seriously, what are you talking about, have you looked for the gmaven-runtime 1.7 artifact?


    org.codehaus.gmaven.runtime
    gmaven-runtime-1.7
    1.2


    Is that what you were looking for? It is in Central.

    ReplyDelete
  4. Thanks Tim,

    I forgot about the groupId change and searched org/codehaus/groovy/maven/runtime/...

    Note that the issue doesn't reference the new groupId neither.

    ReplyDelete