null

NullPointerException, probably…

Maven2 to Gradle Convertor

with 21 comments

Update (04/05/2010):
The code has been refactored from script to class, and it is now hosted on github.
Update (31/07/2010):
Thanks to @lilithapp I have discovered a limitation – your project will be considered multi-module only if your reactor is also a parent of at least one of your modules. I probably won’t fix it, since that’s the case in most projects and since gradle-m2metadata-plugin doesn’t have that limitation.

Last JavaEdge I delivered a session about Java build tools landscape. My impression from this overview is solid – Gradle rocks. It is a best of breed and takes the best from Ant and Maven2, leaving the downsides of both behind. Take at look, it is worth it (Prezi rocks too, but it’s another blog post).

The only fly in the ointment I found is lack of good maven2 to Gradle convention. Gradle has good maven support. First of all, it can use dependenices’ POMs to determine their transitive dependencies. Second, it has Maven plugin, but it works in the opposite direction – it can generate POM for your project, built with Gradle. I need the other side – something similar Gradle has for Ant – ant.importBuild() imports an Ant build into the Gradle project, and each Ant target is treated as a Gradle task. This is cool! Franky, I need much less with Maven.

Here’s the shopping list: I need to generate the following settings from POM.xml

  • Dependencies (inc. scopes and exclusions)
  • Correct plugins selection (e.g. war for web application module)
  • GroupId
  • Version
  • Repositories
  • Compiler level settings
  • All those with full multi-module support
  • All those with reuse support from inheritance and settings.xml

After a short search I discovered JIRA issue GRADLE-154,  in which Antony Stubbs asks for a subset of such functionality, and finally attaches a small Groovy script that parses given POM.xml and dumps to the console dependencies in Gradle format. That was a great start for me, but the drawbacks were obvious – no support for multi-module projects (I can’t recall when I saw single-module project last time), no support for parts, coming from settings.xml, etc. One specific pom.xml file in view has very little to do with the effective pom in runtime. You already got it, right? The parsing should be done on the effective pom, which is easily obtained using maven-help-plugin. So, having effective pom in hand, I can rip it apart and build nice set of build.gradle files, and the settings.gradle for the multi module support, and they include all the items from the above list!

I can assure you there are some bugs here and there in this script, but generally it works, and I managed to migrate fairly complicated project with war assembly, transitive dependencies, poms inheritance, artifacts exclusions etc. in a single click. “Is this cool or is this cool?”

So, grab the script, and give it a shot. It has two flags: -verbose prints out Maven output during effective pom resolution and -keepFile keeps the effective pom file for you.

Note the new task in the generated gradle.build – replacePoms. The idea is to solve the lack of IntelliJ Gradle integration when it comes to dependency management (IDEA knows how to run the build). Gradle generates poms for your modules. The gradle.build knows to copy them to the place where IntelliJ needs them. Just run “build replacePoms”, and IDEA will recognize dependencies from Gradle! Yup!

Enjoy.

P.S. You should check the new gradle-m2metadata-plugin, it’s the real thing – Maven3 embedded  into Gradle’s plugin. It gets all the metadata in runtime!

P.P.S. Sorry for my Groovy, it’s not my mother tongue.

Written by JBaruch

23/02/2010 at 04:29

Posted in Build, Friendly Java Blogs

Tagged with , ,

21 Responses

Subscribe to comments with RSS.

  1. Excellent stuff, Baruch. I think the script approach is anyhow complementary to the future Maven import feature.

    Hans Dockter

    23/02/2010 at 12:56

    • Now we have no choice – it’s already written 🙂

      jbaruch

      23/02/2010 at 13:01

  2. Feel free to ask for my help, Im a native Groovy speaker,

    My mom used to sing me Groovy songs all the time 😉

    Excellent work with Gradle, really cool project indeed.

    Ronen Narkis

    23/02/2010 at 18:50

    • Can you give it a sight then? Spell-check will be much appreciated. Hans thinks about shipping it officially, and I pretty much ashamed with the code quality.

      jbaruch

      23/02/2010 at 22:44

  3. Ill give it a go, is there a maven project that you recommend testing it on? I might reactor it a bit & don’t want to break something along the way

    Ronen Narkis

    24/02/2010 at 22:53

    • I am thinking of some automatic tests, it will be easier to refactor then.
      I’ll update once it will be ready on github. Thanks, dude!

      jbaruch

      24/02/2010 at 23:07

  4. Oh, another nice option would be placing this in github so that you could track changes that I make.

    Ronen Narkis

    24/02/2010 at 22:54

  5. Iv created a gist http://gist.github.com/313851 , its amazing how easy it is to this with github.

    Ronen Narkis

    24/02/2010 at 23:13

  6. […] like ones and improved it a bit to generate usable Gradle build file out of pom. The full story is here. That solution, while definitely is better than void is far from being perfect for number of […]

  7. […] 2 Gradle how to move away from Maven2 to Gradle (using gradle2maven, maven-metadata plugin or even manually). Demo included converting the whole Artifactory project to […]

    PAX 2010 « null

    06/12/2010 at 15:10

  8. I am not sure how to follow this blog as there are just fragments of things to run, so i downloaded Maven2Gradle.groovy as well as maven2gradle-1.0-SNAPSHOT.jar then tried running

    C:\usr\SYNCH\PACKT\3166\Chapters_Code>groovy Maven2Gradle.groovy -keepFile -verbose

    I keep getting this error running the script:

    C:\usr\SYNCH\PACKT\3166\Chapters_Code>groovy Maven2Gradle.groovy -keepFile -verbose
    Working path: C:\usr\SYNCH\PACKT\3166\Chapters_Code\.
    Wait, obtaining effective pom… Caught: : exec returned: 1
    : exec returned: 1
    at org.apache.tools.ant.taskdefs.ExecTask.runExecute(ExecTask.java:646)
    at org.apache.tools.ant.taskdefs.ExecTask.runExec(ExecTask.java:672)
    at org.apache.tools.ant.taskdefs.ExecTask.execute(ExecTask.java:498)
    at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:291)
    at org.apache.tools.ant.dispatch.DispatchUtils.execute(DispatchUtils.java:106)
    at Maven2Gradle.getEffectivePomContents(Maven2Gradle.groovy:365)
    at Maven2Gradle.run(Maven2Gradle.groovy:53)

    C:\usr\SYNCH\PACKT\3166\Chapters_Code>

    I also do know know what batch file you are referring to in this comment:

    “Run maven2gradle batch in the root of the converted project”

  9. So it appears that your direction where ONLY for building from source, but they actually depict just downloading the jar and adding it to gradle which is what I did. Thus there was no batch file.
    I downloaded the batch file then ran it but now it is complaining about and which is already in the gradle/lib DIR

    C:\usr\SYNCH\PACKT\3166\Chapters_Code>maven2gradle
    Working path:C:\usr\SYNCH\PACKT\3166\Chapters_Code

    Wait, obtaining effective pom… Exception in thread “main” java.lang.NoClassDefFoundError: org/apache/tools/ant/BuildException
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:169)
    at org.gradle.tools.Maven2Gradle.class$(Maven2Gradle.groovy)
    at org.gradle.tools.Maven2Gradle.$get$$class$groovy$util$AntBuilder(Maven2Gradle.groovy)
    at org.gradle.tools.Maven2Gradle.geEffectiveContents(Maven2Gradle.groovy:526)
    at org.gradle.tools.Maven2Gradle$geEffectiveContents.callCurrent(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:44)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:141)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:153)
    at org.gradle.tools.Maven2Gradle.convert(Maven2Gradle.groovy:45)
    at org.gradle.tools.Maven2Gradle$convert.call(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:40)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:124)
    at org.gradle.tools.Maven2Gradle.main(Maven2Gradle.groovy:37)
    Caused by: java.lang.ClassNotFoundException: org.apache.tools.ant.BuildException
    at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
    … 15 more

  10. Am I doing something wrong? Fails with …
    Wait, obtaining effective pom… Exception in thread “main” : exec returned: 1
    at org.apache.tools.ant.taskdefs.ExecTask.runExecute(ExecTask.java:646)
    at org.apache.tools.ant.taskdefs.ExecTask.runExec(ExecTask.java:672)
    at org.apache.tools.ant.taskdefs.ExecTask.execute(ExecTask.java:498)
    at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:291)
    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.apache.tools.ant.dispatch.DispatchUtils.execute(DispatchUtils.java:106)
    at groovy.util.AntBuilder.performTask(AntBuilder.java:255)
    at groovy.util.AntBuilder.nodeCompleted(AntBuilder.java:217)
    at groovy.util.BuilderSupport.doInvokeMethod(BuilderSupport.java:147)
    at groovy.util.AntBuilder.doInvokeMethod(AntBuilder.java:171)
    at groovy.util.BuilderSupport.invokeMethod(BuilderSupport.java:64)
    at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.call(PogoMetaClassSite.java:45)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:40)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:128)
    at org.gradle.tools.Maven2Gradle.geEffectiveContents(Maven2Gradle.groovy:530)
    at org.gradle.tools.Maven2Gradle$geEffectiveContents.callCurrent(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:44)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:141)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:153)
    at org.gradle.tools.Maven2Gradle.convert(Maven2Gradle.groovy:45)
    at org.gradle.tools.Maven2Gradle$convert.call(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:40)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:124)
    at org.gradle.tools.Maven2Gradle.main(Maven2Gradle.groovy:37)

    raja Chawat

    31/10/2011 at 20:05

  11. This is amazing tool. Thanks . Gradle rocks!!!!!

    Manoj

    31/05/2012 at 22:33

    • Glad you liked it. Not sure the latest version works with the latest version of Gradle, though. I didn’t have much time to invest into it lately 😦

      jbaruch

      01/06/2012 at 07:43

  12. I have a configuration issue on win7:

    maven2gradle>set | grep _HOME
    GRADLE_HOME=C:\Program Files\gradle\1.1
    GROOVY_HOME=C:\Program Files (x86)\Groovy\Groovy-2.0.1
    JAVA_HOME=C:\Program Files (x86)\Java\jre6

    maven2gradle>maven2gradle
    Exception in thread “main” java.lang.NoClassDefFoundError: groovy/lang/GroovyObject
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClassCond(Unknown Source)
    at java.lang.ClassLoader.defineClass(Unknown Source)
    at java.security.SecureClassLoader.defineClass(Unknown Source)
    at java.net.URLClassLoader.defineClass(Unknown Source)
    at java.net.URLClassLoader.access$000(Unknown Source)
    at java.net.URLClassLoader$1.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    Caused by: java.lang.ClassNotFoundException: groovy.lang.GroovyObject
    at java.net.URLClassLoader$1.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    … 12 more
    Could not find the main class: org.gradle.tools.Maven2Gradle. Program will exit.

    could you please hustle me to the right direction?

    bye

    tpd

    07/09/2012 at 10:10

    • Hi Thomas,
      as you probably know, the maven2gradle is now part of Gradle’s bootsrap plugin. Please post your questions to Gradle’s forums.

      Thanks for trying it out!

      jbaruch

      08/09/2012 at 16:41

      • Hello Baruch,

        thanks for the hint.

        bye
        Thomas

        tpd

        10/09/2012 at 16:16

      • Can you put this information at the TOP of the blog? I didn’t see this comment until I had already spent a lot of time trying to figure things out. I’ve also created a pull request on the github repo with the same information.


Leave a reply to tpd Cancel reply