52

While only for two days now, I am definitely sold on using gradle for all of my Java projects, and drop pom.xml from the root of all my projects.

However, I would like to remain maven-compatible, in the sense that I would like for a gradle task to be able to generate a suitable pom.xml at the root of the project should the user want it.

At this moment, the only reference to a pom.xml I have is in this section of the build.gradle file (this is, with very few modifications, what is found here):

uploadArchives {
    repositories {
        mavenDeployer {
            beforeDeployment {
                MavenDeployment deployment -> signing.signPom(deployment);
            }

            repository(url: sonatypeRepoURI) {
                authentication(userName: sonatypeUsername,
                    password: sonatypePassword);
            }

            pom.project {
                name "${name}";
                packaging "bundle";
                description "${description}";
                url "${projectURL}";

                scm {
                    url "${gitroscm}";
                    connection "${gitroscm}";
                    developerConnection "${gitrwscm}";
                }

                licenses {
                    license {
                        name "Lesser General Public License, version 3 or greater";
                        url "http://www.gnu.org/licenses/lgpl.html";
                        distribution "repo";
                    }
                }

                developers {
                    developer {
                        id "whocares";
                        name "whocares";
                        email "whocares";
                    }
                }
            }
        }
    }
}

How would I extract the pom.project out of this very deeply nested construct into a task which could generate a pom.xml (by default, the generated pom.xml is in build/poms/pom-default.xml and looks quite good)?

More importantly, is it possible to extract that pom.project out of uploadArchives while still being able to refer to it?

Full link to the build.gradle file: here.

fge
  • 119,121
  • 33
  • 254
  • 329
  • Did you look at http://www.gradle.org/docs/current/userguide/maven_plugin.html#N1511A , I haven't used it, but it looks like what you're describing. – jmruc Jun 24 '13 at 18:20
  • @KirilRaychev this looks interesting, but integrating it into the existing execution flow is where I am at a loss :/ – fge Jun 24 '13 at 18:22
  • If you want to build the pom manually, just run the `writeNewPom` task. If you want to generate a pom on each build, add `build.dependsOn writeNewPom` to your `build.grade` – jmruc Jun 24 '13 at 18:26
  • Uh, I already have the maven plugin loaded... And `gradle writeNewPom` fails saying it cannot find the task! – fge Jun 24 '13 at 18:41
  • Work's fine for me - look at this example `build.gradle` - https://gist.github.com/jmruc/5852692 – jmruc Jun 24 '13 at 19:20
  • Does not work for me! Honestly I am really lost here :/ – fge Jun 24 '13 at 19:28
  • @KirilRaychev OK, this was a mistake on my part; can you please post your comments as an answer, with the original link and all? I'll upvote it (previous failures were my fault entirely); now, your sample file generates the pom.xml in `build/`, not at the root... This change and I'll gladly accept it! – fge Jun 24 '13 at 19:37
  • works fine but does not contain any dependencies. How to create pom with dependencies – Shrikant Sep 18 '17 at 06:15
  • @deadpool007 maven manages them automatically; the dependency engines in maven and gradle are pretty similar in that regard. What case did you encounter where dependencies were missing? – fge Sep 18 '17 at 07:31

3 Answers3

73

You can use the gradle maven plugin. This adds the pom convention method to your project, which you can use in a task to generate a pom.xml file, like

task writeNewPom {
    doLast {
        pom {
            project {
                groupId 'org.example'
                artifactId 'test'
                version '1.0.0'
                inceptionYear '2008'
                licenses {
                    license {
                        name 'The Apache Software License, Version 2.0'
                        url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
                        distribution 'repo'
                    }
                }
            }
        }.writeTo("pom.xml")
    }
}

Then you call gradle createPom to generate the pom.xml in the project root. Of all the things in the pom definition, you should really provide groupId, artifactId and version, other thins like licenses are not that important.

You can also look at this example for a project definition with some dependencies, and try running it to see what it produces.

Some of the new keywords were added and some techniques were deprecated. Please check

taranjeetsapra
  • 524
  • 7
  • 19
jmruc
  • 5,714
  • 3
  • 22
  • 41
  • 15
    I got pom file with no dependency :( – IliaEremin Jul 18 '14 at 15:43
  • 14
    How i can get dependency on pom.xml? – Yohanim Sep 25 '14 at 03:59
  • How can I add a properties section? – Christian Goetze Jul 29 '16 at 16:14
  • There is one issue with doing it this way: It will overwrite pom.xml even if the contents are already correct. This makes all later build stages run even when they don't need to, since it changes the file timestamp. (I don't know of a better option either) – Hakanai Jul 12 '17 at 02:43
  • NB: produced an empty POM for a multi-project build. – tekumara Dec 26 '18 at 06:35
  • 3
    `<<` has been deprecated and finally removed in Gradle Version 5.x, so above snippet with raise an exception with recent versions of Gradle. You need to use `Task.doLast()` instead, see also [could-not-find-method-leftshift-for-arguments...](https://stackoverflow.com/questions/55793095/could-not-find-method-leftshift-for-arguments-after-updating-studio-3-4) – Till Kuhn Sep 02 '19 at 13:47
9

Here is my build.gradle

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'maven'

repositories { 
mavenLocal() 
mavenCentral()
}

dependencies {

    compile 'org.springframework:spring-core:4.0.5.RELEASE'
    compile 'org.springframework:spring-webmvc:4.0.5.RELEASE'

    compile 'org.slf4j:slf4j-api:1.7.5'
    runtime 'org.slf4j:slf4j-log4j12:1.7.5'

    testCompile 'org.springframework:spring-test:4.0.5.RELEASE'

    testCompile 'junit:junit:4.11'
    testCompile "org.mockito:mockito-core:1.9.5"
    testCompile "org.hamcrest:hamcrest-library:1.3"

    testCompile 'javax.servlet:javax.servlet-api:3.0.1'
}
test {
  testLogging {
    // Show that tests are run in the command-line output
    events 'started', 'passed'
  }
}
task wrapper(type: Wrapper) { gradleVersion = '1.12' }
task createPom  {
    pom {
        project {
            groupId 'sg.test.spring.web.guide'
            artifactId 'sg-web-initial'
            version '1.0.0-SNAPSHOT'

            inceptionYear '2008'
            licenses {
                license {
                    name 'The Apache Software License, Version 2.0'
                    url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
                    distribution 'repo'
                }
            }
        }
    }.writeTo("pom.xml")
}

You can name the task createPom to anyTaskName as you like. Then just run gradle clean or grale build or simply gradle createPom.

This will generate it as pom.xml in the root of the project. Although you can replace writeTo("pom.xml") with writeTo("<anyDir>/newpom.xml").

The resulting pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
    xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <modelVersion>4.0.0</modelVersion>
    <groupId>sg.test.spring.web.guide</groupId>
    <artifactId>sg-web-initial</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <inceptionYear>2008</inceptionYear>
    <licenses>
        <license>
            <name>The Apache Software License, Version 2.0</name>
            <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
            <distribution>repo</distribution>
        </license>
    </licenses>
    <dependencies>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.0.1</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>4.0.5.RELEASE</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>4.0.5.RELEASE</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.5</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.mockito</groupId>
            <artifactId>mockito-core</artifactId>
            <version>1.9.5</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.5</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>4.0.5.RELEASE</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.hamcrest</groupId>
            <artifactId>hamcrest-library</artifactId>
            <version>1.3</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>
randers
  • 5,031
  • 5
  • 37
  • 64
sanjeev
  • 458
  • 1
  • 6
  • 15
  • 1
    Is it possible to add some lines to build.gradle to generate maven plugin entries in the pom file? – RaGe Mar 18 '15 at 20:38
  • The code here will eagerly create the pom.xml file even if you don't need it. (Should probably have it inside a doLast block) – Hakanai Jul 12 '17 at 02:44
  • @Trejkaz Isn't this only if we call the createPom task? In that case, doesn't that mean we need it? When would doLast make a difference? – Drew Nutter Oct 30 '19 at 22:04
  • 1
    @Drew the current code is writing the file at configuration-time because the call to writeTo is directly inside the task configuration block. Merely configuring the task should be causing the file to get written. (And in this case the configuration is being done eagerly, because tasks.register isn't being used either. If changed to tasks.register, it will likely only configure the task if it's about to actually get run, although even that depends on what else is in the build script.) – Hakanai Nov 01 '19 at 01:35
  • 7
    No dependencies written in the pom.xml – m0skit0 Jan 15 '20 at 10:41
2

Fast forward a few years and a few major Gradle releases, in Gradle 7.5.1 this is how one would approach this with the built-in publishing plugin (latest docs). This has the benefit over hand-writing the pom like above that it automatically gets a lot of the properties, dependencies from the normal Gradle setup:

plugins {
    id("maven-publish")
}
publishing {
    publications {
        maven(MavenPublication) {
            from(components.java)
        }
    }
}
tasks.named("generatePomFileForMavenPublication").configure {
    def publication = publishing.publications.maven
    destination = rootProject.file("${publication.artifactId}-${publication.version}.pom")
}

alternatively without mutating the built-in task we can copy it wherever needed:

tasks.register("copyPomToRoot") {
    def publication = publishing.publications.maven
    def generatePom = tasks.named("generatePomFileFor${publication.name.capitalize()}Publication")
    dependsOn(generatePom)
    def output = rootProject.file("${publication.artifactId}-${publication.version}.pom")
    outputs.file(output)
    doLast { output.bytes = generatePom.get().destination.bytes }
}

As a side-note: if you need a pom.xml, you probably don't just want it in your repo root, but want to publish to a proper maven repository: https://stackoverflow.com/a/70758552/253468.

TWiStErRob
  • 44,762
  • 26
  • 170
  • 254