[GRADLE-154] Create a utility to easily translate Maven dependency lists to Gradle dependency lists - XSLT? Created: 09/Jul/08  Updated: 04/Jan/13  Resolved: 28/Nov/12

Status: Resolved
Project: Gradle
Affects Version/s: None
Fix Version/s: 1.2-rc-1

Type: New Feature
Reporter: Antony Stubbs Assignee: Unassigned
Resolution: Fixed Votes: 9

Attachments: File Maven2Gradle.groovy     File dExtractor.groovy     File maven dependency translator.groovy     XML File pom.xml    

 Description   

Perhaps this could initially easily be done with an XSLT sheet?
It would do two things:
speed up migration from larger Maven projects to Gradle
More easily allow people to try out Gradle on their existing projects



 Comments   
Comment by Antony Stubbs [ 10/Jul/08 ]

ha! who needs XSLT when you've got Groovy!

A simple Groovy script to start you off with the Gradle formatting of dependencies. Just paste in your dependecies section into the script and run. I recommend the Groovy console.

translates:
<dependencies>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>1.5</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.4.3</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.4.3</version>
</dependency>
<!-- work around for jetty commons logging issue -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl104-over-slf4j</artifactId>
<version>1.4.3</version>
</dependency>
</dependencies>

to:
compile: "joda-time:joda-time:1.5"
compile: "org.slf4j:slf4j-api:1.4.3"
compile: "org.slf4j:slf4j-log4j12:1.4.3"
compile: "org.slf4j:jcl104-over-slf4j:1.4.3"

Comment by Hans Dockter [ 10/Jul/08 ]

Very cool.

If we add two things to this we can ship it with 0.3.

  • Mapping the Maven scope to a Gradle configuration
  • Taking the Maven classifier into account. For example "org:testng:testng:1.0:jdk15"

If this could also be wrapped in a unix and windows script which runs against a pom.xml in the current dir that would be awesome.

End of the wishlist

Comment by Antony Stubbs [ 10/Jul/08 ]

Also need to support exclusions? Or is the dep management too different?

Comment by Hans Dockter [ 10/Jul/08 ]

Exclusions would be important. See user's guide: 12.2.3

Comment by Antony Stubbs [ 10/Jul/08 ]

done!

ok - getting more complicated here

This one groups together scopes and adds on classifiers if they are found
It also runs from the command lie and analyses a pom.xml in the same directory

The layout of the scopes could be tweeked-but i'm not yet familiar with how gradle handles them anyway - or what the various scope equivalents are.

excludes are just a test and slightly more complicated formatting away!

I have also included a pretty messed up pom.xml to show it is pretty tolerant.

usage is - put it in your project root ( same as your pom.xml ) and type:
groovy dExtractor.groovy
you'll then get a dump of your deps, grouped into scopes.

Comment by Hans Dockter [ 10/Jul/08 ]

Great. I gonna have a look the code soon.

Scope Mapping:

Maven:Gradle
compile:compile
runtime:runtime
test:testCompile
provided:provided (not implemented yet in Gradle but soon)

Comment by Antony Stubbs [ 10/Jul/08 ]

Done!

Added exclusion support and corrected scope mapping.

I'm getting faster with this groovy stuff

The test pom.xml included produces this output (please let me know if it's wrong):

output
Working path:C:\workspaces\mavenDepConvert\src\.
compile: "c3p0:c3p0:0.9.1.2"
compile: "com.fonterra.tams:msg-classes:1.0.0"
compile: "oracle.jdbc.driver:OracleDriver:10.2.0.3"
addDependency(['compile'], "org.apache.struts:struts-core:1.3.8") {
   exclude(module: 'commons-logging')
}
addDependency(['compile'], "org.apache.struts:struts-extras:1.3.8") {
   exclude(module: 'commons-logging')
}
addDependency(['compile'], "org.apache.struts:struts-taglib:1.3.8") {
   exclude(module: 'commons-logging')
}
addDependency(['compile'], "org.apache.ibatis:ibatis-sqlmap:2.3.0") {
   exclude(module: 'commons-logging')
}
addDependency(['compile'], "org.springframework:spring-web:2.5") {
   exclude(module: 'commons-logging')
}
addDependency(['compile'], "org.springframework:spring-beans:2.5") {
   exclude(module: 'commons-logging')
}
addDependency(['compile'], "org.springframework:spring-jdbc:2.5") {
   exclude(module: 'commons-logging')
}
addDependency(['compile'], "org.springframework:spring-orm:2.5") {
   exclude(module: 'commons-logging')
}
addDependency(['compile'], "org.hibernate:hibernate:3.2.5.ga") {
   exclude(module: 'commons-logging')
}
compile: "commons-lang:commons-lang:2.3"
compile: "javax.xml.bind:jaxb-api:2.1"
compile: "opensymphony:sitemesh:2.3"
addDependency(['compile'], "displaytag:displaytag:1.1") {
   exclude(module: 'commons-logging')
}
compile: "javax.jms:jms:1.1"
compile: "joda-time:joda-time:1.5"
compile: "org.slf4j:slf4j-api:1.4.3"
compile: "org.slf4j:slf4j-log4j12:1.4.3"
compile: "org.slf4j:jcl104-over-slf4j:1.4.3"
compile: "log4j:log4j:1.2.14"
compile: "org.apache.commons:commons-io:1.3.2"
compile: "jscience:jscience:4.3.1"
compile: "org.google:google-collect:0.20071022-BETA"
compile: "taglibs:standard:1.1.2"
runtime: "com.sun.xml.bind:jaxb-impl:2.0.3"
runtime: "cglib:cglib:2.1_3"
testCompile: "org.easymock:easymock:2.3"
testCompile: "org.easymock:easymockclassextension:2.2.2:jdk14"
addDependency(['testCompile'], "org.dbunit:dbunit:2.2") {
   exclude(module: 'commons-logging')
}
testCompile: "junit:junit:4.4"
addDependency(['testCompile'], "org.openqa.selenium.client-drivers:selenium-java-client-driver:${selenium-version}") {
   exclude(module: 'commons-logging')
   exclude(module: 'selenium-server')
   exclude(module: 'selenium-server-coreless')
}
addDependency(['testCompile'], "org.openqa.selenium.server:selenium-server:${selenium-version}") {
   exclude(module: 'commons-logging')
}
provided: "javax.servlet:jstl:1.1.2"
provided: "javax.servlet:servlet-api:2.5"
provided: "javax.servlet:jsp-api:2.0"
system: "com.ibm:WebSphere-Runtime:6.1.0.13"}}
Comment by Antony Stubbs [ 11/Jul/08 ]

Added license (correct one?) and comments.

Comment by Antony Stubbs [ 11/Jul/08 ]

Added gradle formated project group and version (what else can we add? - where is a reference similar to the maven pom reference with all the things we can optionally conifgure?)
updated test pom.xml

Comment by Antony Stubbs [ 11/Jul/08 ]
$ groovy ../../../mavenDepConvert/src/converter.groovy
Working path:c:\workspaces\jbossMavenPlugin\jboss\jboss-server-manager\.

Project settings:
project.group = 'org.jboss.jbossas'
project.version = 'jboss-server-manager

Dependency information:
compile: "org.apache.commons:commons-io:1.3.2"
Comment by Antony Stubbs [ 11/Jul/08 ]

typo

Comment by Antony Stubbs [ 12/Jul/08 ]

omg - did i have my eyes shut when i wrote that?
bug fix - project.version = .., now uses version not artifactId

Comment by Hans Dockter [ 12/Jul/08 ]

version = 'jboss-server-manager' will do. Any assignment gets automatically delegated to the project object.

To provide the user a better out of the box experience it would be cool to have start scripts for this, which adds the groovy jar which is shipped with Gradle to the classpath. That way the user does not need to have Gradle installed. And we have a defined Groovy version we run against.

Could you imagine to do this? If not I'm also happy to do this.

Comment by Hans Dockter [ 12/Jul/08 ]

We use launch4j to provide windows start scripts. This is for example used in the build.gradle file of Gradle.

Comment by Hans Dockter [ 12/Jul/08 ]

Some more details:

Your transformer code would live in a new package in the gradle-core src called for example org.gradle.mvn2gradle. Our build would generate a jar just out of this package. Our build would also generate two scripts, mvn2gradle and mvn2gradle.exe for starting the command under *nix and windows. Those scripts would be part of the Gradle bin directory. For this your script would need to move into a class. This class might be wrapped by a Mvn2GradleMain class for argument processing (I'm sure eventually we will have some). Last but not least it would be important to have a test.

Does this makes sense?

Comment by Antony Stubbs [ 13/Jul/08 ]

Yup - sweet as. Is this already done anywhere yet, that I could use as an example?

Comment by Hans Dockter [ 13/Jul/08 ]

We do the same for the Gradle start scripts. Have a look in the build.gradle of Gradle.

StartScriptsGenerator.generate("$archivesBaseName-${version}.jar", explodedDistBinDir, archivesBaseName) This is were we generate the *nix start script. StartScriptsGenerator is a class from buildSrc.

This is were we create the windows exe:

logger.info('Generate launch4j windows exe.')
        String launch4jDistName = "launch4j-" + launch4jVersion
        createLaunch4j(explodedDistLaunch4jLibDir, launch4jDistName)
        try {
            ant.taskdef(
                name: "launch4j",
                    classname: "net.sf.launch4j.ant.Launch4jTask",
                    classpath: "$buildDir/$launch4jDistName/launch4j.jar:$buildDir/$launch4jDistName/lib/xstream.jar")
            ant.launch4j() {
                config(headerType: "console", outfile: "$explodedDistBinDir/gradle.exe",
                        dontWrapJar: "true", jarPath: "../lib/" + archive_jar.archiveName) {
                    jre(minVersion: "1.5.0", jdkPreference: 'jdkOnly')
                }
            }
        } catch (Exception e) {
            logger.warning("The windows start exe could not be generated. Possibly you run the build on a machine with an OS which is not Linux, Mac OS X or Windows.")
            logger.warning(e.getMessage());
        }
Comment by Baruch Sadogursky [ 23/Nov/09 ]

New version - MavenDependencyExtractor.groovy

Added support for multi-module POMs, inheritance, dependency management, properties - everything.

Uses maven-help-plugin, so have it in local repo or have an Internet connection

Enjoy.

P.S. "-verbose" (w/o quotes) to see the output of maven-help-plugin execution

Comment by Hans Dockter [ 30/Nov/09 ]

Thanks Baruch, this is excellent stuff, Baruch. That script should be either shipped with Gradle 0.9 or made available in a prominent way. I will start a discussion on the dev list on that soon and put you in cc. Maven 3 should provide additional means of integrating Maven projects into Gradle, Maven 3 is supposed to be very easy to embedd. What would be very nice, is to include a pom.xml at runtime. Either just for the dependencies or as a complete project. The latter could wrap Maven goals and lifecycle phases as Gradle tasks. Have you had a look at Maven 3?

Comment by Baruch Sadogursky [ 30/Nov/09 ]

Hans, I am not sure I understood what do you mean by "include a pom.xml at runtime either just for the dependencies or as a complete project".
Considering Maven3 - yap, looks like it will be very simple to embed it and to get all the information about build from it.

Anyway, we just had the JavaEdge09 conference (biggest annual Java conference in Israel) and I made a talk about modern build tools, featuring Gradle, of course. It included a demo on migrating from Maven2 to Gradle (that's what I needed the script for).
This is the presentation - http://prezi.com/ngwwf1wcfn7n/
I am planing to record the whole talk, or at least to blog about the demo details, but I don't know when I'll get into it.

Comment by Hans Dockter [ 30/Nov/09 ]

Hi Baruch,

just reading my very cryptic comment (I have written that in a rush). Apologies for that.

With your script you can transform a maven pom.xml in a build.gradle file. Which is very helpful and might be exactly what people want if they want to migrate to Gradle.

But there are other scenarios where people want to stick with the pom.xml. For example if you want to integrate an active Maven project in your multi-project Gradle build. Our vision for Gradle is also to be a build integration tool. I have seen a couple of situations where people had a mix of Maven and Ant builds and they wanted to have a single multi-project build for them. They ended up using CI tools for that. Our idea is that you can use Gradle to orchestrate any kind of build. With Ant builds this is already possible.

For Ant projects you can already say in build.gradle.

ant.import('build.xml')

It would be very handy if you could do:

maven.importDependencies('pom.xml') or maven.import('pom.xml')

The first would add dynamically the dependencies of the pom.xml to the Gradle project object. The latter would to the same plus creating a number of Gradle tasks that wrap Maven lifecycle phases and goals. Have a look at the Ant import described in the user's guide. That way you can not just integrate Maven projects but also add functionality to them from Gradle.

Does that make sense?

Comment by Baruch Sadogursky [ 30/Nov/09 ]

Oh, yeah. Lot's of sense. Frankly, I have expected this functionality to exist in a first place, and turned to this script only as a hack when didn't find one. If such functionality will be present in Gradle that would be a huge selling point.

Meanwhile, I hacked the other direction too - in order to maintain pom.xml dependencies (for IntelliJ) I use the Gradle's Maven plugin to generate pom and then copy it (inside the build) to the root directory. Then I have my build in Gradle, and my IntelliJ happy with up-to-date dependencies in pom.xml

Comment by Baruch Sadogursky [ 22/Feb/10 ]

Kind of complete Maven2 to Gradle conversion script. More details here: http://jbaruch.wordpress.com/2010/02/23/maven2-to-gradle-convertor

Comment by Hans Dockter [ 23/Feb/10 ]

I'm wondering what is the best way to roll it out. It would be nice to provide a good out-of-the-box experience. One way to achieve that would be to have a Maven2Gradle.bat/shell script. Those scrips would use the groovy shipped with Gradle to run the Maven2Gradke groovy script.

I guess something like the following could be used in the script: java -cp libs/groovy-....jar SomeGroovyStarterClass Maven2Gradle.groovy

Comment by Bob Herrmann [ 31/Aug/10 ]

why not just put the groovy script into a task somewhere.

Then a maven user can do

$ gradle createBuildScriptFromPom

or

C:> gradle createBuildScriptFromPom

Comment by Baruch Sadogursky [ 31/Aug/10 ]

@Bob, I am not sure it should be Gradle task. Gradle builds your code, while this script "builds" your build.
Currently, fully blown maven metadata plugin is in the works. By using it your build will be able to take all the metadata from your pom.

Comment by Bob Herrmann [ 02/Sep/10 ]

@Baruch understood. I was mostly thinking that not having to twiddle with or install something else would help get to the nice "out-of-the-box" experience that we want.

I'm sitting looking at a pom.xml I'm thinking whats that gradle thing I heard about. How many mental steps are required to get that build running in gradle? 1. download gradle 2. configure GRADLE_HOME and PATH 3. find something to convert pom to build.gradle 4. install that 5. run it 6. gradle build 7. book vacation in paradise Would be nice to get 1 and 7 closer.

Comment by Baruch Sadogursky [ 03/Sep/10 ]

@Bob sure, the points 3-5 are just temporary solution. Soon it will be 1,2, 3.write 3 lines build.gradle to include maven-metadata-plugin, 6,7.

Comment by Chris Beams [ 03/Sep/10 ]

To Bob's ease-of-use comments, I too would like to see this functionality available directly from `gradle`. Whether it's using some variant of Baruch's approach, XSLT, or the forthcoming embedded Maven support, the point is that the 'how' should be an implementation detail to the user, who simply expresses through a convenient CLI 'what' he or she wants to do. In this case, the 'what' is converting an existing (set of) pom(s) to Gradle script(s).

I say when in doubt, ask yourself "what would Git do"? Git would certainly integrate this as a subcommand, something like `gradle convert`. Because doing such a conversion could be arbitrarily complex with many options, Git would also likely provide an interactive mode (`gradle convert -i`).

I think Git is a shining example of command-line power and usability. We should strive to make Gradle's CLI just as inclusive and even more user friendly. Gradle is about more than 'building your code'. The vision is that Gradle is your one stop for project automation needs. If a conversion from Maven is something that Gradle intends to support, then I'd say that's right in the core `gradle` executable's wheelhouse.

Supporting such features suggests that Gradle's CLI needs to expand a bit. Perhaps 'everything is a task', but as-is, that wouldn't be too friendly to the user. Hans and Adam have already been discussing this, but Gradle needs to somehow accomodate things like per-task options, a structure that feels like Git's subcommands, etc.

Comment by Hans Dockter [ 28/Sep/10 ]

Eventually we will putt this functionality in the maven plugin. Plus in the future you will be able to call a plugin from the command line without applying it from the build script. That way Gradle will provide a good solution for this.

Comment by Daz DeBoer [ 28/Nov/12 ]

This feature is included in the new Bootstrap plugin: http://www.gradle.org/docs/current/userguide/bootstrap_plugin.html#N13E69

Comment by Antony Stubbs [ 28/Nov/12 ]

Awesome!

What's the way to go the other way again? To generate a pom? Would be nice to have that snippet of info here too.

haha, cool, my 4 year old little issue

Comment by Baruch Sadogursky [ 29/Nov/12 ]

Antony, using Maven plugin's install task generates pom file. All you need to do is configure the location. http://www.gradle.org/docs/current/userguide/maven_plugin.html
You can also tweak the pom at will.

Thanks for inception what eventually became the Bootstrap plugin

Generated at Wed Jun 30 11:23:06 CDT 2021 using Jira 8.4.2#804003-sha1:d21414fc212e3af190e92c2d2ac41299b89402cf.