Need a more "gradle way" to handle my downloaded zip full of jars

I have working code that downloads a zip file from a maven repository and unzips it to a local directory to be used as a compile dependency. What I have works, but it seems hokey and doesn’t scale to multiple projects well. I’d rather rely on the task output to set up the dependencies. Is there a better way to handle my downloaded zip full of jars to the dependencies?

apply plugin: "java"


dependencies {

   	compile group: 'com.company', name: 'MyZipFullOfJars', version: '5.0.1', ext: 'zip'	
	compile fileTree(dir: 'my-libs', include: '*.jar')
      
}

task installDependencies(type: Sync) {
    configurations.compile.resolvedConfiguration.resolvedArtifacts.each { artifact ->
        if (artifact.file.name.contains('jar')) {
            from zipTree(artifact.file)
            into 'my-libs'
        }
    }
}
assemble.dependsOn('installDependencies')

You’ve got a lot of the right ideas.

I’d try something like this:

apply plugin: "java"

configurations {
    zipped
}

dependencies {
    zipped group: 'com.company', name: 'MyZipFullOfJars', version: '5.0.1', ext: 'zip'	
    compile files({ tasks.installDependencies.extractedJars })
}

task installDependencies(type: Sync) {
    def extractDir = "${buildDir}/my-libs"
    
    ext.extractedJars = fileTree(extractDir) {
        include "**/*.jar"
        builtBy "installDependencies"
    }

    dependsOn configurations.zipped
    from { 
        configurations.zipped.collect { zipTree(it) }
    }
    into extractDir
}

// just for checking that it worked
task printClasspath {
    dependsOn configurations.compile
    doLast {
        configurations.compile.each {
            println it
        }
    }
}

Key points

  • Keep your downloaded zip out of the configurations that java adds. This makes it easier to use later.
  • Use { closures } to delay some things (like getting the tasks before they’re defined)
  • Avoid resolving the dependencies in the configuration phase with closures again
  • Since you need to apply a filter to the outputs, it’s easier to add an extra property as a FileTree on installDependencies and use that for your dependencies.

If you needed something like installDependencies in multiple projects, it would be time to break out a custom task type.

2 Likes

Can you provide more details on your use case?

  • Is the ZIP file provided by an external organization/project?
  • Do you have full control over the published ZIP file?
  • Wouldn’t it be easier to publish the individual parts of the ZIP file and then directly refer to them in your dependencies declaration?

Thanks this is exactly what I was looking for. I learned something new as I didn’t know you could reference a property (ext.extractedJars) as owned by a task like that. I think I may use this in another project.

bmuschko, These jars are from a 3rd party which we are manually publishing to our organization’s internal Artifactory. The 3rd party doesn’t follow any version conventions either from their manifest or a POM file. I would prefer to upload the individual jars, but I do not know how our 3rd party individually versions their jar files (I don’t want to create fiction). This also allows us to publish included ReadMe’s without repackaging their jar files.

I dig how there are more and less “gradle” ways of doing things.

I’d ask the 3rd party company/organization to add a version number to the artifacts. They might actually have one but just take it off before delivering them. Maybe they are simply not aware that you want a version number and would be happy to add it. Generally speaking, not using a version number for artifacts is a bad practice.

It sounds to me as if there also isn’t any metadata attached to the artifacts. If that’s the case, it should be easy for you to simply use the current timestamp as version number and publish the artifacts to your internal repo. That will give you an idea on when you received the artifacts and clearly identifies them in your repo with a version.

Hi Thanks for this answer.
I am trying this solution and I am getting error.
Could not get unknown property ‘’ for task set.
Looks like this is happening because I am trying to use this task before I have defined it.
Please let me know how to resolve this issue.