Search code examples
javagradlejardependenciestransitive-dependency

Gradle include transitive dependencies in directory


I have a java project which has a couple of dependencies, e.g.:

dependencies {
    compile("com.whatever.jar:jar-1:1.2.3")
    compile("com.whatever.jar:jar-2:4.5.6")
    compile("com.whatever.jar:jar-3:7.8.9")
} 

I package it as a jar library and publish it to the repository together with a POM file that describes those dependencies:

<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/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.my.project</groupId>
    <artifactId>my-library</artifactId>
    <version>1.0.0</version>
    <dependencies>
        <dependency>
            <groupId>com.whatever.jar</groupId>
            <artifactId>jar-1</artifactId>
            <version>1.2.3</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>com.whatever.jar</groupId>
            <artifactId>jar-2</artifactId>
            <version>4.5.6</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>com.whatever.jar</groupId>
            <artifactId>jar-3</artifactId>
            <version>7.8.9</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>
</project>

I also have another project which depends on this previously built jar on compile time:

dependencies {
    compileOnly("com.my.project:my-library:1.0.0")
}

I would like to create a task that builds the second project and creates a zip file containing both com.my.project:my-library:1.0.0 jar and its transitive dependencies (jar-1, jar-2 and jar-3).

task createZip << {
    into('lib') {
        // here I would like to do something like (it's a horrible pseudo-code):
        from configurations.(com.my.project:my-library:1.0.0).jar.transitiveDependencies.files
    }
}

How do I achieve that?

Edit: I also would like to access the list of my-library's transitive dependencies (and precisely those, not any other dependencies in the project) programmatically in order to build a Loader-Path manifest attribute using those.


Solution

  • Here’s a self-contained build.gradle script which demonstrates how your createZip task (which only adds specific dependencies to the ZIP archive) can be created:

    /* make the "compileOnly" configuration available */
    plugins {
        id 'java'
    }
    
    /* add some demo dependencies to the project */
    repositories {
        jcenter()
    }
    dependencies {
        compileOnly 'junit:junit:4.12'
        compileOnly 'org.slf4j:slf4j-simple:1.7.28'
    }
    
    task createZip(type: Zip) {
        // the "lib" directory in the ZIP file will only have all those dependency
        // files of the "compileOnly" configuration which belong to the
        // "junit:junit:4.12" module:
        def depOfInterest = dependencies.create('junit:junit:4.12')
        into('lib') {
            from configurations.compileOnly.resolvedConfiguration.getFiles({dep ->
                dep == depOfInterest
            })
        }
    
        // the "justForDemonstration" directory in the ZIP file will have all
        // dependency files of the "compileOnly" configuration, incl. SLF4J:
        into('justForDemonstration') {
            from configurations.compileOnly
        }
    }
    

    This can be run with ./gradlew createZip (tested with Gradle 5.6.2). It produces the ZIP file under build/distributions/<your_project_name>.zip. Let me know if that’s what you had in mind with your pseudocode.