Stubbisms – Tony’s Weblog

July 11, 2008

Groovy converter from Maven to Gradle Dependencies [GRADLE-154]

Filed under: Java — Tags: , , — Antony Stubbs @ 11:03 am

I raised an issue on Gradle jira the other day – so I thought I would fix it.

It is a groovy script that takes a pom.xml in the current directory, reads the dependencies and outputs Gradle formatted dependencies.

The Jira issue is here:
http://jira.codehaus.org/browse/GRADLE-154

It’s a work in progress, but it’s looking pretty good so I thought I’d post it here. Groovy rocks btw!
(btw, I gave up trying to get wordpress to stop trying to insert smiley faces. if you want the actual code, go to the jira issue)

Basically it works in a few steps.

  1. First step is to read in the pom.xml file and get it’s text into a string – easy.
  2. Next is to use the Groovy XmlSlurper library to parse the text string and get a reference to the outer project element.
  3. Then we can use GPath to navigate the object hierarchy and retrieve the collection of dependency nodes.
  4. Then using Groovy Looping and mapping a Groovy Closure to each element, we collect together all the dependency nodes into corresponding collections depending on their scope value.
  5. Next we define some utility functions that I will go over soon.
  6. Then for each collection, one at a time, we take each element and call our print function.
  7. The print function then checks the exclusions node to see if it exists, if so it branches off, otherwise we call our simple print function.
  8. Both print functions use GStrings to construct the print statements.
  9. The complex print statement does one extra task which is iterate over each ‘exclusion’ node and print out the artifact id.
/*
 * Copyright 2007 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * This script takes the pom.xml in the current directory, reads the from it dependencies
 * and outputs Gradle formatted dependencies.
 *
 * It currently is quite simplistic and does not perform any checks on inherited
 * dependencies or retreive version numbers from variables deplared in the pom.
 *
 * @author Antony Stubbs <antony.stubbs@gmail.com>
 */

// debug - print out our current working directory
println "Working path:" + new File(".").getAbsolutePath()

// read in the pom.xml file and get it’s text into a string
pomContent = new File("pom.xml").text

// use the Groovy XmlSlurper library to parse the text string and get a reference to the outer project element.
def project = new XmlSlurper().parseText(pomContent)

// use GPath to navigate the object hierarchy and retrieve the collection of dependency nodes.
def dependencies = project.dependencies.dependency

def compileTimeScope = []
def runTimeScope = []
def testScope = []
def providedScope = []
def systemScope = []

// using Groovy Looping and mapping a Groovy Closure to each element, we collect together all
// the dependency nodes into corresponding collections depending on their scope value.
dependencies.each() {
    def scope = (elementHasText(it.scope)) ? it.scope : "compile"
    switch (scope) {
        case "compile":
            compileTimeScope.add(it)
            break
        case "test":
            testScope.add(it)
            break
        case "provided":
            providedScope.add(it)
            break
        case "runtime":
            runTimeScope.add(it)
            break
        case "system":
            systemScope.add(it)
            break
    }
}

/**
 * print function then checks the exclusions node to see if it exists, if
 * so it branches off, otherwise we call our simple print function
 */
def printGradleDep = {String scope, it ->
    def exclusions = it.exclusions.exclusion
    if (exclusions.size() > 0) {
        printComplexDependency(it, scope)
    } else {
        printBasicDependency(it, scope)
    }
}

/**
 * complex print statement does one extra task which is iterate over each
 * ‘exclusion’ node and print out the artifact id.
 */
private def printComplexDependency(it, scope) {
    println "addDependency(['${scope}'], \"${contructSignature(it)}\" ) {"
    it.exclusions.exclusion.each() {
        println "   exclude(module: '${it.artifactId}')"
    }
    println "}"
}

/**
 * Print out the basic form og gradle dependency
 */
private def printBasicDependency(it, String scope) {
    def classifier = contructSignature(it)
    println "${scope}: \"${classifier}\""
}

/**
 * Construct and return the signature of a dependency, including it's version and
 * classifier if it exists
 */
private def contructSignature(it) {
    def gradelDep = "${it.groupId.text()}:${it.artifactId.text()}:${it?.version?.text()}"
    def classifier = elementHasText(it.classifier) ? gradelDep + ":" + it.classifier.text().trim() : gradelDep
    return classifier
}

/**
 * Check to see if the selected node has content
 */
private boolean elementHasText(it) {
    return it.text().length() != 0
}

// for each collection, one at a time, we take each element and call our print function
compileTimeScope.each() { printGradleDep("compile", it) }
runTimeScope.each() { printGradleDep("runtime", it) }
testScope.each() { printGradleDep("testCompile", it) }
providedScope.each() { printGradleDep("provided", it) }
systemScope.each() { printGradleDep("system", it) }

Which converts this:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
<parent>
		<groupId>asdfsafd</groupId>
		<artifactId>asdfsafd</artifactId>
		<version>asdfsadf</version>
		<relativePath>../pom.xml</relativePath>
	</parent>

	<groupId>awf3</groupId>
	<artifactId>asf</artifactId>
<packaging>asfe</packaging>
	<name>asfeasef</name>
<profiles>
<profile>
			<id>jetty</id>
			<activation>
<property>
					<name>jetty</name>
				</property>
			</activation>
			<dependencies>
				<!-- For local data source -->
				<dependency>
					<groupId>oracle.jdbc.driver</groupId>
					<artifactId>OracleDriver</artifactId>
					<version>10.2.0.3</version>
					<!-- <version>11.1.0.6</version> -->
					<scope>compile</scope>
				</dependency>
				<dependency>
					<groupId>javax.jms</groupId>
					<artifactId>jms</artifactId>
					<version>1.1</version>
					<scope>compile</scope>
				</dependency>
			</dependencies>
		</profile>
	</profiles>

	<!-- All the commons logging exclusions can be removed now -->
	<dependencies>
		<!-- Used in JUnit tests -->
		<dependency>
			<groupId>org.easymock</groupId>
			<artifactId>easymock</artifactId>
			<version>2.3</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.easymock</groupId>
			<artifactId>easymockclassextension</artifactId>
			<version>2.2.2</version>
			<scope>test</scope>
			<classifier>jdk14</classifier>
		</dependency>
		<!-- WebSphere library. Compile time dependency from OracleUtils in order to
			unwrap connections to call Oracle's setSessionTimezone for
			TIMESTAMP WITH LOCAL TIME ZONE data type. -->
		<dependency>
			<groupId>com.ibm</groupId>
			<artifactId>WebSphere-Runtime</artifactId>
			<version>6.1.0.13</version>
			<scope>system</scope>
			<!-- the following path must be on on one line-->
			<systemPath>
				c:/progra~1/IBM/SDP70/runtimes/base_v61/plugins/com.ibm.ws.runtime_6.1.0.jar
			</systemPath>
		</dependency>
		<!-- Connection pooling and testing (keep-alive) -->
		<dependency>
			<groupId>c3p0</groupId>
			<artifactId>c3p0</artifactId>
			<version>0.9.1.2</version>
			<scope>compile</scope>
		</dependency>
		<!-- JaxB Message classes -->
		<dependency>
			<groupId>com.fonterra.tams</groupId>
			<artifactId>msg-classes</artifactId>
			<version>1.0.0</version>
		</dependency>
		<!-- Compile dependency and used for testing. Is provided in WS environment -->
		<dependency>
			<groupId>oracle.jdbc.driver</groupId>
			<artifactId>OracleDriver</artifactId>
			<version>10.2.0.3</version>
			<!-- <version>11.1.0.6</version> -->
			<scope>compile</scope>
		</dependency>
		<dependency>
			<groupId>org.apache.struts</groupId>
			<artifactId>struts-core</artifactId>
			<version>1.3.8</version>
			<exclusions>
				<exclusion>
					<groupId>commons-logging</groupId>
					<artifactId>commons-logging</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>org.apache.struts</groupId>
			<artifactId>struts-extras</artifactId>
			<version>1.3.8</version>
			<exclusions>
				<exclusion>
					<groupId>commons-logging</groupId>
					<artifactId>commons-logging</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>org.apache.struts</groupId>
			<artifactId>struts-taglib</artifactId>
			<version>1.3.8</version>
			<exclusions>
				<exclusion>
					<groupId>commons-logging</groupId>
					<artifactId>commons-logging</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>org.apache.ibatis</groupId>
			<artifactId>ibatis-sqlmap</artifactId>
			<version>2.3.0</version>
			<exclusions>
				<exclusion>
					<groupId>commons-logging</groupId>
					<artifactId>commons-logging</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-web</artifactId>
			<version>2.5</version>
			<exclusions>
				<exclusion>
					<groupId>commons-logging</groupId>
					<artifactId>commons-logging</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-beans</artifactId>
			<version>2.5</version>
			<exclusions>
				<exclusion>
					<groupId>commons-logging</groupId>
					<artifactId>commons-logging</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-jdbc</artifactId>
			<version>2.5</version>
			<exclusions>
				<exclusion>
					<groupId>commons-logging</groupId>
					<artifactId>commons-logging</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-orm</artifactId>
			<version>2.5</version>
			<exclusions>
				<exclusion>
					<groupId>commons-logging</groupId>
					<artifactId>commons-logging</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate</artifactId>
			<!-- 			<version>3.3.0-SNAPSHOT-TAMS-CUSTOM</version> -->
			<version>3.2.5.ga</version>
			<scope>compile</scope>
			<exclusions>
				<exclusion>
					<groupId>commons-logging</groupId>
					<artifactId>commons-logging</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>commons-lang</groupId>
			<artifactId>commons-lang</artifactId>
			<version>2.3</version>
		</dependency>
		<!-- Not used by application - only used by jax bean generator -->
		<!--
			<dependency>
			<groupId>com.sun.xml.bind</groupId>
			<artifactId>jaxb-xjc</artifactId>
			<version>2.0.3</version>
			</dependency>
		-->
		<!-- Used at com.fonterra.tams.util.SchemaUtil.init(SchemaUtil.java:65) -->
		<dependency>
			<groupId>com.sun.xml.bind</groupId>
			<artifactId>jaxb-impl</artifactId>
			<version>2.0.3</version>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>javax.xml.bind</groupId>
			<artifactId>jaxb-api</artifactId>
			<version>2.1</version>
			<scope>compile</scope>
		</dependency>
		<dependency>
			<groupId>opensymphony</groupId>
			<artifactId>sitemesh</artifactId>
			<version>2.3</version>
		</dependency>

		<dependency>
			<groupId>displaytag</groupId>
			<artifactId>displaytag</artifactId>
			<version>1.1</version>
			<exclusions>
				<exclusion>
					<groupId>commons-logging</groupId>
					<artifactId>commons-logging</artifactId>
				</exclusion>
			</exclusions>
		</dependency>

		<dependency>
			<groupId>javax.jms</groupId>
			<artifactId>jms</artifactId>
			<version>1.1</version>
			<scope>compile</scope>
		</dependency>
		<dependency>
			<groupId>org.dbunit</groupId>
			<artifactId>dbunit</artifactId>
			<version>2.2</version>
			<scope>test</scope>
			<exclusions>
				<exclusion>
					<groupId>commons-logging</groupId>
					<artifactId>commons-logging</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.4</version>
			<scope>test</scope>
		</dependency>

		<dependency>
			<groupId>org.openqa.selenium.client-drivers</groupId>
			<artifactId>selenium-java-client-driver</artifactId>
			<version>${selenium-version}</version>
			<scope>test</scope>
			<exclusions>
				<exclusion>
					<groupId>commons-logging</groupId>
					<artifactId>commons-logging</artifactId>
				</exclusion>
				<exclusion>
					<groupId>org.openqa.selenium.server</groupId>
					<artifactId>selenium-server</artifactId>
				</exclusion>
				<exclusion>
					<groupId>org.openqa.selenium.server</groupId>
					<artifactId>selenium-server-coreless</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>org.openqa.selenium.server</groupId>
			<artifactId>selenium-server</artifactId>
			<version>${selenium-version}</version>
			<scope>test</scope>
			<exclusions>
				<exclusion>
					<groupId>commons-logging</groupId>
					<artifactId>commons-logging</artifactId>
				</exclusion>
			</exclusions>
		</dependency>

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

		<!--
			<dependency>
			<groupId>commons-logging</groupId>
			<artifactId>commons-logging</artifactId>
			<version>1.1.1</version>
			</dependency>
		-->
		<dependency>
			<groupId>log4j</groupId>
			<artifactId>log4j</artifactId>
			<version>1.2.14</version>
		</dependency>
		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-io</artifactId>
			<version>1.3.2</version>
		</dependency>
		<dependency>
			<groupId>jscience</groupId>
			<artifactId>jscience</artifactId>
			<version>4.3.1</version>
		</dependency>
		<dependency>
			<groupId>org.google</groupId>
			<artifactId>google-collect</artifactId>
			<!-- version represents Google's snapshot release date
				(we don't want to use SNAPSHOT qualifier because there
				isn't anything to qualify it to yet. -->
			<version>0.20071022-BETA</version>
		</dependency>
		<!-- Hibernate optional dependency -->
		<dependency>
			<groupId>cglib</groupId>
			<artifactId>cglib</artifactId>
			<version>2.1_3</version>
			<scope>runtime</scope>
		</dependency>
		<!-- Used by JSP pages -->
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jstl</artifactId>
			<version>1.1.2</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>taglibs</groupId>
			<artifactId>standard</artifactId>
			<version>1.1.2</version>
		</dependency>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>servlet-api</artifactId>
			<version>2.5</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jsp-api</artifactId>
			<version>2.0</version>
			<scope>provided</scope>
		</dependency>
	</dependencies>

	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>commons-logging</groupId>
				<artifactId>commons-logging</artifactId>
				<version>99.0-does-not-exist</version>
			</dependency>
			<dependency>
				<groupId>commons-logging</groupId>
				<artifactId>commons-logging-api</artifactId>
				<version>99.0-does-not-exist</version>
			</dependency>
		</dependencies>
	</dependencyManagement>
<properties>
		<l2>[2,)</l2>
		<l1>[1,)</l1>
		<selenium-version>0.9.2</selenium-version>
		<basedir>/</basedir>
	</properties>

	<repositories>
		<repository>
			<id>no-commons-logging</id>
			<name>No-commons-logging Maven Repository</name>
			<layout>default</layout>
			<url>http://no-commons-logging.zapto.org/mvn2</url>
		</repository>
		<repository>
			<releases />
			<id>local</id>
			<name>local</name>
			<url>file:///${basedir}/m2Repository</url>
		</repository>
		<repository>
			<id>openqa-repository</id>
			<name>OpenQA Repository</name>
			<url>http://maven.openqa.org/</url>
		</repository>
	</repositories>

</project>

To output which looks like this:

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"}}
Advertisements

1 Comment »

  1. […] 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 […]

    Pingback by Maven2 to Gradle Convertor « null — May 11, 2010 @ 3:09 am


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Blog at WordPress.com.

%d bloggers like this: