Make new "fat" jar with every build


(John Wilson) #1

I have a Gradle build system that almost does everything I want. This includes putting all of the dependency class files in my JAR (ie, making a “fat” jar file). The problem I’m having is if new class files have been compiled for a dependency, then my Gradle project will itself build new class files (yay!) but it does not create a new jar file (bummer…). What I want it to do is if new dependency class files are available then this project should create a new jar file - whether or not any of the source files for this Gradle project have been changed. Alternatively, I would accept a brute force solution: create a new jar every time a build is run.

Thank you for any help!

Here is my build.gradle

defaultTasks 'build'
apply plugin: 'java'

targetCompatibility = '1.7'
sourceCompatibility = '1.7'

// JAR settings
// Specify ".doFirst" to force this to run in the Execution phase.  Without
// this specification, this would be run during the Configuration phase, which
// would fail if CTlib.jar didn't yet exist; at Execution phase, CTlib.jar
// should have been created already.
jar.doFirst {
    // Create a "fat jar" file which includes all the dependencies
    // The following was taken from a nice simple example found at:
    // https://newfivefour.com/gradle-hello-world-java-fat-jar.html
    from {
        (configurations.runtime).collect {
            it.isDirectory() ? it : zipTree(it)
        }
    }
    
    // Build up a string containing all the runtime dependencies; this will be
    // used as the 'Class-Path' string in the manifest instead of hard-wiring
    // library names
    StringBuilder sb = new StringBuilder();
    project.configurations.runtime.each {
        sb.append(it.name + ' ')
    }
    String runtimeDependenciesStr = sb.toString().trim()
    
    manifest {
        attributes 'Main-Class': 'ctserver.CTserver',
                   'Class-Path': runtimeDependenciesStr
    }
}

repositories {
    flatDir {
    	// Location of CTlib.jar
    	dirs "$rootProject.projectDir/CTlib/build/libs"
    }
}

dependencies {
	// Build CTlib project first, because we use CTlib.jar
	compile project(':CTlib')
	// Specify that we use CTlib.jar
    compile name: 'CTlib'
}

// Not sure it is needed, but we have the copy done last (specified by using
// "<<") to make sure the new jar file gets copied, not the old/original one 
build << {
	String fromLoc = "${buildDir}/libs/CTserver.jar"
	String toLoc = "../../CloudTurbineAndroid/Common"
	println "Copy library from " + fromLoc + " to " + toLoc
	copy {
		from fromLoc
        into toLoc
	}
}

(Dimitar Dimitrov) #2

Use http://imperceptiblethoughts.com/shadow if you still have the dependency problem, please report to this thread (if possible with a running example) and add this bruteforce hack:

tasks.shadowJar.inputs.dir  "$rootProject.projectDir/CTlib/build/libs"

(John Wilson) #3

Thank you! Using shadowJar solved my problem. If a dependency has changed or if one of this project’s own source code files has changed, then a new JAR is created.