Gradle: package multi-project into a single jar

fatjargradle

I have a gradle multi-project and want to create a single jar (library) containing all the classes of my subprojects and external dependencies.

I have the following project structure. Each project has its own 3rd party dependencies. Common dependencies are included in the root project. The two modules A and B are dependent on the core.

+ root-project (only build.gradle and settings.gradle)
  - core       (src/main/java, src/main/resources, ..)
  - module-A   (src/main/java, src/main/resources, ..)
  - module-B   (src/main/java, src/main/resources, ..)

To export a single jar, I added the following task to the build.gradle of the root project:

apply plugin: "java"

subprojects.each { subproject -> evaluationDependsOn(subproject.path)}

task allJar(type: Jar, dependsOn: subprojects.jar) {
    baseName = 'multiproject-test'
    subprojects.each { subproject ->
        from subproject.configurations.archives.allArtifacts.files.collect {
            zipTree(it)
        }
    }
}

artifacts {
    archives allJar
}

This approach works, but does only collect the project source files. The 3rd party dependencies are ignored. So I tried out the Shadow Plugin (http://imperceptiblethoughts.com/shadow/) which should also include external dependencies.

Unfortunately the plugin does not collect anything at all. This is most probably due to missing dependencies between the root project and its sub projects. How can I tell the shadow plugin, that it should collect the sources of the subprojects? Or is there a better approach to export a single library out of multiple projects?

complete build.gradle using the shadow plugin:

/****************************************
 * instructions for all projects
 ****************************************/
allprojects {
    apply plugin: 'idea'
    apply plugin: 'eclipse'

    group = 'com.test.multi-project'
    version = '1.0'
}

/****************************************
 * instructions for each sub project
 ****************************************/
subprojects {
    apply plugin: "java"

    sourceCompatibility = 1.9
    targetCompatibility = 1.9

    repositories {
        mavenCentral()
    }

    dependencies {
        compile "org.slf4j:slf4j-api:1+"
        compile "ch.qos.logback:logback-core:1+"
        compile "ch.qos.logback:logback-classic:1+"

        testCompile "junit:junit:4+"
    }
}

/****************************************
 * Single jar out of all sub projects
 ****************************************/
buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.github.jengelman.gradle.plugins:shadow:2.0.2'
    }
}

apply plugin: 'com.github.johnrengelman.shadow'
apply plugin: 'java'

shadowJar {
    baseName = 'multiproject-test'
} 

The submodules are included in the settings.gradle of the root project

rootProject.name = 'myproject-root'

// submodules
include ":core"

include ":module-A"
include ":module-B"

Thanks for your help!

Best Answer

I solve my problem with the solution explained here: https://discuss.gradle.org/t/how-to-get-gradle-install-to-actually-bundle-all-project-subproject-classes-resources-etc/12070/4

My build.gradle looks now like this:

/****************************************
 * instructions for all projects
 ****************************************/
allprojects {
    apply plugin: 'idea'
    apply plugin: 'java'

    repositories {
        mavenCentral()
    }

    group = 'com.test.multiproject'
    version = '1.0'

    sourceCompatibility = 1.9
    targetCompatibility = 1.9
}

/****************************************
 * instructions for each sub project
 ****************************************/
subprojects {

    // common dependencies
    dependencies {
        compile "org.slf4j:slf4j-api:1+"
        compile "ch.qos.logback:logback-core:1+"
        compile "ch.qos.logback:logback-classic:1+"

        testCompile "junit:junit:4+"
    }
}

/****************************************
 * Single library jar containing all sub projects and 3rd party dependencies
 ****************************************/
configurations {
    childJars
}

dependencies {
    subprojects.each {
        childJars project(it.path)
    }
}

jar {
    dependsOn configurations.childJars
    from { configurations.childJars.collect { zipTree(it) } }
}