Extract jar file and use as a dependency in subprojects

I want to download a zip file that contains, among other things, a jar file. I want to extract the jar and then reference the jar file as a resource (using flat file, for instance). Then my subprojects should be able to use the file as a depedency.

I’ve got the follow task that does the trick of extracting the jar file. I’m just using the referenced zip file as an example. In reality, the zip file could be from a local build or from a hosted bamboo build. In other words, the zip file is a moving target that is not published to an archive until it is released.

My question is how can I get this task to run, and run only once, before my subprojects that use this file as a dependency are evaluated?

My top-level build.gradle:

def DOWNLOAD_URL = "http://download.oracle.com/otn_software/samples/cloud/iotcs-csl-javase-bin-18.3.5.0.0-12.zip"

 task getDeviceLibrary(type: Copy) {

    def File tmpDir = new File(buildDir, "tmp")
    mkdir tmpDir

    def File libsDir = new File(buildDir, "libs")
    mkdir libsDir

    def File dest = new File(tmpDir, "iotcs-csl-javase-bin-18.3.5.0.0-12.zip")
    new URL(DOWNLOAD_URL).withInputStream{is -> dest.withOutputStream{ it << is }}

    from zipTree(dest)
    include "iotcs/csl/javase/lib/device-library.jar"
    into tmpDir

    doLast {
        // move device-library.jar to build/libs
        def File source = new File(tmpDir, "iotcs/csl/javase/lib/device-library.jar")
        def File sink = new File(libsDir, "device-library.jar")
        source.withInputStream{is -> sink.withOutputStream{ it << is }}
        //delete tmpDir
    }   

}

Then, in my subprojects I want to reference the jar as a dependency.

Another approach might be to declare dependencies on a project that supplies the extracted jar instead of trying to declare dependencies on the extracted jar directly. This way, the project supplying the jar will look like any other subproject that builds a jar, but instead of compiling it you download and extract it.

extractedJar/build.gradle:

apply plugin: 'base'

// For interest, I also re-worked your example task to do all work
// during task execution and support up-to-date checks.
task getDeviceLibrary {
    ext {
        downloadURL = 'http://download.oracle.com/otn_software/samples/cloud/iotcs-csl-javase-bin-18.3.5.0.0-12.zip'
        fileToExtract = 'iotcs/csl/javase/lib/device-library.jar'
        destFile = new File( buildDir, 'libs/device-library.jar' )
    }

    inputs.property( 'downloadURL', downloadURL )
    inputs.property( 'fileToExtract', fileToExtract )
    outputs.file( destFile )

    doLast {
        File destDir = destFile.parentFile
        destDir.mkdirs()

        File downloadFile = new File( temporaryDir, 'download.zip' )
        new URL( downloadURL ).withInputStream { is ->
            downloadFile.withOutputStream { it << is }
        }

        project.copy {
            from( zipTree( downloadFile ) )
            into( destDir )
            include( fileToExtract )
            includeEmptyDirs = false
            eachFile { details ->
                if( details.sourcePath == fileToExtract ) {
                    details.path = destFile.name
                }
            }
        }
    }
}

artifacts {
    'default'( tasks.getDeviceLibrary.destFile ) {
        builtBy tasks.getDeviceLibrary
    }
}

settings.gradle:

include 'extractedJar'

build.gradle:

apply plugin: 'java'
dependencies {
    implementation project( ':extractedJar' )
}
task showFiles {
    ext {
        config = configurations.compileClasspath
    }
    inputs.files( config )
    doLast {
        println config.join('\n')
    }
}

Output:

$ gradle showFiles
> Task :extractedJar:getDeviceLibrary
> Task :showFiles
C:\Users\Chris Dore\Projects\extractedJar\extractedJar\build\libs\device-library.jar
1 Like

Educational, elegant, and awesome! Thanks a ton!