Maven vs Grails

We have a Grails 1.1 which uses ant + Ivy as its build mechanism. The Ivy configuration has always been wonky, I wasn’t the person who set it up so I’m not exactly sure why it is that way. You would have to run this special ant target, “copy-jars”, which movies the libraries downloaded with Ivy around because some grails command would delete them. When it came time to upgrade to the latest version, Grails 1.2.2, we wanted to address this problem. One of the new features touted for this release is its maven integration and since we use Maven for several of our other projects we figured this would be a good choice.

Our experiment upgrading to Grails 1.2.2 with Maven integration took a few days to work our way through the errors and gotchas. In the end we were able to “successfully” upgrade our project – it compiled and passed all the tests. However it didn’t work that well. I’ve included my notes from the upgrade at the end of the post for anyone else who’s trying to do something similar. However in the end Grails + Maven integration sucked for a few reasons.

  • Tests will fail if you do not run a mvn clean in-between. So you can’t run mvn test, fix something then, re-run mvn test again and expect it to work.

  • Running the mvn package command required a larger amount of memory. I had to increase memory available via JAVA_TOOL_OPTIONS=-Xmx512m. This wasn’t required for our old Ivy-based build system nor is it required when using a pure grails build.

  • The build is fragile, minor changes would break in unexpected ways. But the worst part is any errors encountered were always hidden behind java invocation errors masking the real error. This makes debugging the build much harder.

  • In general the integration is very immature, maybe in the future this will improve. But at this state if I can’t recommend this to anyone.

In the end we decided that Maven integration just wasn’t worth it, and we needed something better. The next option we looked at was a pure grails-based build system. This option worked well, there we’re no errors or gotchas like the previous experiment. The best part is that it is able to pull dependencies from Maven without dealing with maven! It’s pretty simple, as described in the manual, just set your dependencies into grails-app/conf/BuildConfig.groovy. That’s it, you’re done. Run “grails compile” and you’re dependencies will be downloaded and the application compiled. This just took a an hour to figure it all out and show it working compared to the days it took getting the Maven integration barely working. In the end I highly recommend using a pure-grails based build, it is a 1000 times better than the traditional Maven integration.

Grails + Maven Notes

Here are the notes I took during the upgrade to Grails + Maven

  1. Since no one has released Maven archetypes for Grails 1.2.2 we have to first upgrade using Maven to 1.2.0, then later upgrade to 1.2.2. Really how much different can the archetype be between these minor point versions?

  2. Update you’re ~/.m2/settings.xml to include a reference to the Maven plugins for Grails.

    <plugingroups>
        <plugingroup>org.grails</pluginGroup>
    </pluginGroups>
    
  3. Create a new pom.xml file for the project.

    mvn grails:create-pom –DgroupId=[groupId] -DartifactId=[artifactId]
    

    You’ll probably want to open the pom.xml file and add a few additional entries such as <name>, <description>, <url>, etc.

  4. Next add your project’s dependencies into the pom.xml. This is obviously going to be very different for each project. But here are a few errors that I ran into for our specific project.

    Our project uses Xerces and Xalan for some XML processing, however these API’s conflicted with the Grails-based commands and their dependency on these libraries. Below is the error that I received (hopefully to help anyone searching for this error on Google). To fix the problem I needed to exclude our projects version of Xerces and Xalan and use the Grails version of these libraries.

    Embedded error: java.lang.reflect.InvocationTargetException
    loader constraint violation: when resolving overridden method "org.apache.
    xerces.jaxp.SAXParserImpl.getXMLReader()Lorg/xml/sax/XMLReader;" the
    class loader (instance of org/codehaus/groovy/grails/cli/support/
    GrailsRootLoader) of the current class, org/apache/xerces/jaxp/
    SAXParserImpl, and its superclass loader (instance of <bootloader>),
    have different Class objects for the type org/xml/sax/XMLReader
    used in the signature
    

    The second gotcha was our dependency on dumbster:dumbster:1.6 which records dependencies on both javax.activation:1.0.2 and javax.mail:mail:1.3.2 both of which have entries in the Maven central repository but no artifacts exists with the entries. It’s weird, you can get the pom.xml files but not the actual jar files. I fixed this by adding in dependencies for the new versions of both libraries.

  5. Run the maven upgrade command. In theory you should just run “mvn grails:exec -Dcommand="upgrade”, but theory doesn’t always work. There’s some bug with running the upgrade command, it will fail with the following error:

    Embedded error: java.lang.reflect.InvocationTargetException
    /Users/scott/Development/Eclipse/Workspaces3.5/DSpace/trunk/null/src/war not found.
    

    To get around this you will need to install Grails, and run the upgrade command directly.

    GRAILS_HOME=/path/to/temporary/grails/home
    cd <project/dir>
    $GRAILS_HOME/bin/grails upgrade
    unset GRAILS_HOME
    
  6. Check your plugins. You can use “mvn grails:list-plugins” to get your current list. Then use “mvn grails:uninstall-plugin –DpluginName=<name>” and “mvn grails:install-plugin –DpluginName=”<name> <version>”.

  7. Remove the old build system’s such as any build.xml files left over.

  8. Change the pom.xml files to reference the latest version of Grails. You should also use the same steps from step 5 to run the Grails upgrade command.


comments powered by Disqus