[SOLVED] How to unzip a RuntimeDependency and rebuild it again in a sub-parallel module?

Hi All

I have a weird requirement. I have looking into generating secondary JARs from a single Gradle project. I have written a Gradle task that perform this task.

Unfortunately this secondary JAR requires a slightly different Manifest and the only idea I have to unpack the primary JAR and rebuild it again in a second module. This is because the second JAR must also have a different GAV coordinate.

Suppose, I have

acme-core/src/main/java/uk/gov/acme          /*Java source code*/
acme-core/acme-core.jar                             /* is the primary JAR */
acme-core/acme-core-client.jar                    /* is the secondary JAR (alternative manifest and same source file) */

Now I believe the best way is to split this build.gradle into two separate modules and therefore Gradle will understand the different GAVs.

Build the primary Jar

acme-core/build.gradle                                /* acme-core:1.0 */

Build the second Jar

acme-core-client/build.gradle                        /* acme-core-client:1.0 */

The secondary build file will have a runtime dependency, because there is no source code to compile.

runtime "acme:acme-core:1.0" 

In order to write the single task in the secondary gradle file, I want to know how to find the primary dependency artifact and then unzip it to a folder build/unzip-dependency, then I can re-JAR it as the secondary artifact.


PS: I also tried to answer this stack overflow question: http://stackoverflow.com/questions/20008324/gradle-multiple-jars-from-single-source-folder/30477258#30477258

If you want to create another jar with just a different manifest you can do that in a single project.

task clientJar(type: Jar) {
    appendix = 'client'
    from sourceSets.main.output
    manifest {
        // configure the manifest

If you want to publish that other Jar with a unique GAV you’ll want to create a separate publication for it.

Yes Mark you are correct there.

If your second JAR is also dependency somewhere else in the multi-module Gradle then YMMV.

My solution was to create a parallel or separate module acme-core-client.

In this build.gradle, create a task to find the dependency from the classpath and unzip it. Remove the offending MANIFEST.MF with the `Class-Path’ property. Add new entries to the distributon using some other private client specific tasks.

    task repack {
        ext.unzipDir = "build/unzip-dependency"
        outputs.file unzipDir

        doLast {
            def dependencyFiles =  configurations.runtime.findAll { File file ->
                if (file.getName().startsWith("acme-core-${version}")) {
                    logger.info( "**** Found the dependency file: [" + file.getName() + "]" )

            def dependencyFile = dependencyFiles[0]
            ant.mkdir( dir: unzipDir )
            ant.unzip( src: dependencyFile, dest: unzipDir )
            ant.delete( file: "$unzipDir/META-INF/MANIFEST.MF")
            /* Bring in other stuff */

(PS: Raise a GradleException if you don’t find the dependency)

With the exploded directory, we then simply JAR this up with a new manifest

    jar {
        manifest {
                    "Main-Class": platformMainClass,
                    "Implementation-Title": platformDisplayName,
                    "Implementation-Description": platformDescription,
                    "Implementation-Version": version,
                    "Implementation-Type": "CLIENT",

        duplicatesStrategy = DuplicatesStrategy.EXCLUDE

        from 'build/unzip-dependency'

        include '**/*'

        exclude( [ 'log4j*.properties', 'acme/private/**' ])

Make sure the JAR task depends on the repack task.


At least now, we have a real dependency u.gov.acme:acme-core-client:1.0 and this works for the other project modules.