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 you 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.

Tags: , , , ,

3 Responses to “Maven vs Grails”

  1. Kareem Covington says:

    Great read! You may want to follow up on this topic :D

  2. Satappa says:

    Hi, Am facing the same error “Embedded error: java.lang.reflect.InvocationTargetException ” , what do u mean by “use the Grails version of these libraries.” ??

  3. Scott says:

    Satappa,

    What I mean by “use the Grails version of these libraries?” is to exclude the conflicting libraries from dependencies.

    First, what you need to do is find the pom file for the dependency you’re using and look at it’s dependency. Chances are the dependency it’s probably listed mvnrepository.com. You can search for it there then navigate to the pom file.

    Second, examine the pom file for any suspicious dependency. Like I pointed out in the post most commonly there are XML libraries like xerces or xalan. If you have an error message that might also help you track down the offending dependency.

    Third, once you’ve identified an offending dependency then you’ll want to exclude it from your application. There are two methods if you’re using the grails-based BuildConfig.groovy then you can do something like:

    compile ('net.sourceforge.htmlunit:htmlunit:2.4') {
    excludes 'xercesImpl','xmlParserAPIs'
    }

    Or if your project is maven-based then you’ll do something like:

    <dependency>
    <groupId>net.sourceforge.htmlunit</groupId>
    <artifactId>htmlunit</artifactId>
    <version>2.4</version>
    <exclusions>
    <exclusion>
    <groupId>xerces</groupId>
    <artifactId>xercesImpl</artifactId>
    </exclusion>
    <exclusion>
    <groupId>xerces</groupId>
    <artifactId>xmlParserAPIs</artifactId>
    </exclusion>
    </exclusions>

    </dependency>

    Hope this helps,
    Scott–

Leave a Reply