How to get `gradle install` to actually bundle all project, subproject classes, resources, etc?

When I gradle install my multiproject, the JAR it puts into ~/.m2 doesn’t contain any of the classes built by the project/subprojects. I expected the Maven plugin to configure jar/install to do this, but no luck so far.

Could someone offer an example build.gradle configuration such that gradle install behaves more like mvn install, jar-ing ALL class files and inserting that into ~/.m2 ?

This configuration builds a basic multiproject jar, and inserts it correctly in ~/.m2.

subprojects.each { subproject ->
  evaluationDependsOn(subproject.path)
}
task mmJar(type: Jar, dependsOn: subprojects.jar) {
  subprojects.each { subproject ->
    from subproject.configurations.archives.artifacts.files.collect {
      zipTree(it)
    }
  }
}
install.dependsOn mmJar

How can I alter this to integrate shadowJar, so that it’s not just a multiproject jar, but a multiproject jar with all the subproject’s dependencies as well? zipTree can’t seem to find the *-all.jars.

1 Like

Here’s a build.gradle configuration that assembles a fat jar for a multiproject, and correctly installs that to ~/.m2.

plugins {
  id 'com.github.johnrengelman.shadow' version '1.2.2'
}

allprojects {
  apply plugin: 'java'
  apply plugin: 'maven'
  apply plugin: 'com.github.johnrengelman.shadow'

  artifacts {
    archives shadowJar
  }
}

subprojects.each { subproject ->
  evaluationDependsOn(subproject.path)
}
task multiprojectJar(type: Jar, dependsOn: subprojects.assemble) {
  subprojects.each { subproject ->
    from subproject.configurations.archives.artifacts.files.collect { file ->
      zipTree(file)
    }
  }
}
artifacts {
  archives multiprojectJar
}

Unfortunately, declaring shadowJar’s as artifacts results in gradle build becoming really slow (20+ sec), even for a small multiproject.

Is there a way to configure the list of artifacts, but only when certain tasks are run (so gradle assemble/gradle build skips shadowJars)?

You should be able to create a fatjar w/ dependencies without using the shadowjar plugin.

apply plugin: 'java'

configurations {
  childJars
}

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

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

That creates a circular dependency.

Why is gradle so bad at such a basic use case?

The mmJar trick works relatively well for multiprojects, except even it can’t resolve gradle’s failure, except the mere existence of a rootProject makes gradle install create an empty (no classes) jar in .m2. The workaround for that is to not use a rootProject, instead placing such classes in a child project like “…-common”.

So the mmJar trick works as long as you avoid using a rootProject (e.g. don’t use ~/Desktop/yourproject/src/…).

//
// Fix gradle install for multiprojects
//

subprojects.each { subproject ->
  evaluationDependsOn(subproject.path)
}
task mmJar(type: Jar, dependsOn: subprojects.jar) {
  subprojects.each { subproject ->
    from subproject.configurations.archives.artifacts.files.collect {
      zipTree(it)
    }
  }
}
install.dependsOn mmJar
1 Like