44

I'm using Gradle to help automate Hadoop tasks. When calling Hadoop, I need to be able to pass it the path to some jars that my code depends on so that Hadoop can send that dependency on during the map/reduce phase.

I've figured out something that works, but it feels messy and I'm wondering if there's a feature I'm missing somewhere.

This is a simplified version of my gradle script that has a dependency on the solr 3.5.0 jar, and a findSolrJar task that iterates through all of the jar files in the configuration to find the right one:

apply plugin: 'groovy'

repositories {
    mavenCentral()
}

dependencies {
    compile 'org.apache.solr:solr-solrj:3.5.0'
}

task findSolrJar() {
     println project.configurations.compile*.toURI().find { URI uri -> new File(uri).name == 'solr-solrj-3.5.0.jar'}
}

running this gives me output like this:

gradle findSolrJar                                                                                                                                                                                                                                                           
file:/Users/tnaleid/.gradle/caches/artifacts-8/filestore/org.apache.solr/solr-solrj/3.5.0/jar/74cd28347239b64fcfc8c67c540d7a7179c926de/solr-solrj-3.5.0.jar
:findSolrJar UP-TO-DATE

BUILD SUCCESSFUL

Total time: 2.248 secs

Is there a better way to do this?

Ted Naleid
  • 26,511
  • 10
  • 70
  • 81

5 Answers5

34

Your code can be simplified a bit, for example project.configurations.compile.find { it.name.startsWith("solr-solrj-") }.

Peter Niederwieser
  • 121,412
  • 21
  • 324
  • 259
33

You can also create a dedicated configuration for an artifact, to keep it clean; and use asPath if the fact that it can potentially return several locations works well for your use case (happens if it resolves same jar in several locations):

configurations {
  solr
}

dependencies {
  solr 'org.apache.solr:solr-solrj:3.5.0'
}

task findSolrJars() {
  println configurations.solr.asPath
}

To avoid copy-paste, in case you as well need that jar in compile configuration, you may add this dedicated configuration into compile one, like:

dependencies {
  solr 'org.apache.solr:solr-solrj:3.5.0'
  compile configurations.solr.dependencies
}
Tim
  • 12,318
  • 7
  • 50
  • 72
4

I needed lombok.jar as a java build flag to gwt builds this worked great !

configurations { 
 lombok
}
dependencies {
  lombok 'org.projectlombok:lombok+'
} 
ext {
   lombok = configurations.lombok.asPath
}

compileGwt {
  jvmArgs "-javaagent:${lombok}=ECJ"
}

I was surprised that the resolution worked early enough in the configuraiton phase, but it does.

DALDEI
  • 3,722
  • 13
  • 9
1

Here is how I did it:

project.buildscript.configurations.classpath.each {
    String jarName = it.getName();
    print jarName + ":"
}
djangofan
  • 28,471
  • 61
  • 196
  • 289
0

I recently had this problem as well. If you are building a java app, the problem at hand is normally that want to get the group:module (groupId:artifactId) to path-to-jar mapping (i.e. the version is not a search criteria as in one app there is normally only one version of each specific jar).

In my gradle 5.1.1 (kotlin-based) gradle build I solved this problem with:

var spec2File: Map<String, File> = emptyMap()
configurations.compileClasspath {
    val s2f: MutableMap<ResolvedModuleVersion, File> = mutableMapOf()
    // https://discuss.gradle.org/t/map-dependency-instances-to-file-s-when-iterating-through-a-configuration/7158
    resolvedConfiguration.resolvedArtifacts.forEach({ ra: ResolvedArtifact ->
        s2f.put(ra.moduleVersion, ra.file)
    })
    spec2File = s2f.mapKeys({"${it.key.id.group}:${it.key.id.name}"})
    spec2File.keys.sorted().forEach({ it -> println(it.toString() + " -> " + spec2File.get(it))})
}

The output would be some like:

:jing -> /home/tpasch/scm/db-toolchain/submodules/jing-trang/build/jing.jar
:prince -> /home/tpasch/scm/db-toolchain/lib/prince-java/lib/prince.jar
com.github.jnr:jffi -> /home/tpasch/.gradle/caches/modules-2/files-2.1/com.github.jnr/jffi/1.2.18/fb54851e631ff91651762587bc3c61a407d328df/jffi-1.2.18-native.jar
com.github.jnr:jnr-constants -> /home/tpasch/.gradle/caches/modules-2/files-2.1/com.github.jnr/jnr-constants/0.9.12/cb3bcb39040951bc78a540a019573eaedfc8fb81/jnr-constants-0.9.12.jar
com.github.jnr:jnr-enxio -> /home/tpasch/.gradle/caches/modules-2/files-2.1/com.github.jnr/jnr-enxio/0.19/c7664aa74f424748b513619d71141a249fb74e3e/jnr-enxio-0.19.jar

After that, it is up to you to do something useful with this Map. In my case I add some --path-module options to my Java 11 build like this:

val patchModule = listOf(
        "--patch-module", "commons.logging=" +
        spec2File["org.slf4j:jcl-over-slf4j"].toString(),

        "--patch-module", "org.apache.commons.logging=" +
        spec2File["org.slf4j:jcl-over-slf4j"].toString()
)
patchModule.forEach({it -> println(it)})

tasks {
        withType<JavaCompile> {
            doFirst {
                options.compilerArgs.addAll(listOf(
                        "--release", "11",
                        "--module-path", classpath.asPath
                ) + patchModule)
                // println("Args for for ${name} are ${options.allCompilerArgs}")
            }
        }
}
aanno
  • 638
  • 8
  • 17