gradle - how do I build a jar with a lib dir with other jars in it?
Asked Answered
G

10

74

In gradle - how can I embed jars inside my build output jar in the lib directory (specifially the lib/enttoolkit.jar and lib/mail.jar)?

Gastric answered 10/8, 2010 at 3:28 Comment(3)
#4872156Gimcrack
Does this answer your question? Creating runnable JAR with GradleSerafinaserafine
I much prefer this over flattening hundreds of class files into the root jar (which seems to be more common).Rogerson
M
41

If you have all the jars inside a directory (lets call it libs) in your project, you only need this:

jar {
    into('lib') {
        from 'libs'
    }
}

I guess it is more likely that these jars are dependencies of some sort. Then you could do it like this:

configurations {
    // configuration that holds jars to copy into lib
    extraLibs
}
dependencies {
    extraLibs 'org.something:something-dep1:version'
    extraLibs 'org.something:something-dep2:version'
}

jar {
    into('lib') {
        from configurations.extraLibs
    }
}
Mention answered 20/2, 2012 at 10:26 Comment(4)
If you want all the dependencies, you can also copy from configurations.runtime, which gives you the default compile dependencies, saving you the trouble of creating your own extraLibs configuration.Straight
Error: Could not find method jar() for arguments [build_bndovev91pu8trwrdngc8qh7i$_run_closure5@3be2321e] on project ':app' of type org.gradle.api.Project.Malcommalcontent
@Straight To get all dependencies, I had to copy from configurations.runtimeClasspath rather than configurations.runtime, while avoiding the need for the extraLibs definition.Adaline
We just need to add resource after srcDirs processResources{ from(zipTree("src/main/resources/lib/local-jar-name.jar")) }Null
H
36

Lifted verbatim from: http://docs.codehaus.org/display/GRADLE/Cookbook#Cookbook-Creatingafatjar

Gradle 0.9:

jar {
    from configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
}

Gradle 0.8:

jar.doFirst {
    for(file in configurations.compile) {
        jar.merge(file)
    }
}

The above snippets will only include the compile dependencies for that project, not any transitive runtime dependencies. If you also want to merge those, replace configurations.compile with configurations.runtime.

EDIT: only choosing jars you need

Make a new configuration, releaseJars maybe

configurations {
    releaseJars
}

Add the jars you want to that configuration

dependencies {
    releaseJars group: 'javax.mail', name: 'mail', version: '1.4'
    //etc
}

then use that configuration in the jar task outlined above.

Hatpin answered 10/8, 2010 at 15:7 Comment(7)
I am on 0.9rc1. so tried your first suggestion. Pulled in all sorts of stuff I didn't want.....Gastric
closer I think...problem is I need the jars in a lib directory. This pulls in the classes from the jars. I want lib/mail and lib/enttoolkit in the output jarGastric
this works... sort of: sourceSets { main { java { srcDir "$wepTrunk/osgi/mycompany.osgi.server/src" } resources { srcDir "/Users/phil/dev/trunk/osgi/mycompany.osgi.server/lib" } } } it puts the jars from my /users/phil/dev/trunk/osgi/mycompany.osgi.server/lib in my output jar, but not in a "lib" directory. Any ideas how to get them in a lib dir?Gastric
I know this didn't answer the question, but a wonderful wonderful tip. Thanks lucas.Rohr
Great tip, but completely misses the pretty pretty specific question.Emogeneemollient
The link is not available due to "All Codehaus services have been terminated"Malcommalcontent
pls, update the answer since "from" requires curly braces: see https://mcmap.net/q/47040/-using-gradle-to-build-a-jar-with-dependenciesFabianfabianism
B
23

simple:

task copyToLib( type: Copy ) {
    into "$buildDir/libs/lib"
    from configurations.runtime
}

jar { dependsOn copyToLib }

run it:

$ gradle jar
...
$ tree build/libs

build/libs
├── your-project-0.0.1.BUILD-SNAPSHOT.jar
└── lib
    ├── akka-actor-2.0.jar
    ├── akka-camel-2.0.jar
    ├── ... ... ...
    ├── spring-expression-3.1.0.RELEASE.jar
    └── zmq-2.1.9.jar

1 directory, 46 files
Broeder answered 19/3, 2012 at 15:18 Comment(1)
This copies the libraries into the output directory, but not into the JAR file itself -- which was the question.Isomerous
B
8

I also needed to do something similar and wasn't quite able to get what Guus and stigkj suggested working, but got close enough with their help to get this working (Guus' example blew up on the dependencies { compile { extendsFrom myLibs }} closure for me.

apply plugin: 'groovy'

repositories {
    mavenCentral()
}

configurations {
    // custom config of files we want to include in our fat jar that we send to hadoop
    includeInJar
}

dependencies {
    includeInJar 'org.codehaus.groovy:groovy:1.8.6'

    configurations.compile.extendsFrom(configurations.includeInJar)
}

jar {
    into('lib') {
        println "includeInJar: " + configurations.includeInJar.collect { File file -> file }
        from configurations.includeInJar
    }

}

Then running gradle jar and examining the created jar gives me this output, showing that I get the jar file to have groovy as well as all jars that it's dependent on inside the "fat jar":

%  gradle jar                                                                                                                         
includeInJar: [/Users/tnaleid/.gradle/caches/artifacts-8/filestore/org.codehaus.groovy/groovy/1.8.6/jar/553ca93e0407c94c89b058c482a404427ac7fc72/groovy-1.8.6.jar, /Users/tnaleid/.gradle/caches/artifacts-8/filestore/antlr/antlr/2.7.7/jar/83cd2cd674a217ade95a4bb83a8a14f351f48bd0/antlr-2.7.7.jar, /Users/tnaleid/.gradle/caches/artifacts-8/filestore/asm/asm/3.2/jar/9bc1511dec6adf302991ced13303e4140fdf9ab7/asm-3.2.jar, /Users/tnaleid/.gradle/caches/artifacts-8/filestore/asm/asm-tree/3.2/jar/cd792e29c79d170c5d0bdd05adf5807cf6875c90/asm-tree-3.2.jar, /Users/tnaleid/.gradle/caches/artifacts-8/filestore/asm/asm-commons/3.2/jar/e7a19b8c60589499e35f5d2068d09013030b8891/asm-commons-3.2.jar, /Users/tnaleid/.gradle/caches/artifacts-8/filestore/asm/asm-util/3.2/jar/37ebfdad34d5f1f45109981465f311bbfbe82dcf/asm-util-3.2.jar, /Users/tnaleid/.gradle/caches/artifacts-8/filestore/asm/asm-analysis/3.2/jar/c624956db93975b7197699dcd7de6145ca7cf2c8/asm-analysis-3.2.jar]
:compileJava UP-TO-DATE
:compileGroovy UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:jar

BUILD SUCCESSFUL

Total time: 3.387 secs

%  jar tvf build/libs/gradletest.jar                                                                                                  
     0 Mon Mar 12 11:40:00 CDT 2012 META-INF/
    25 Mon Mar 12 11:40:00 CDT 2012 META-INF/MANIFEST.MF
     0 Mon Mar 12 11:40:00 CDT 2012 lib/
5546084 Mon Mar 05 13:13:32 CST 2012 lib/groovy-1.8.6.jar
445288 Mon Mar 05 13:13:38 CST 2012 lib/antlr-2.7.7.jar
 43398 Mon Mar 05 13:13:40 CST 2012 lib/asm-3.2.jar
 21878 Mon Mar 05 13:13:40 CST 2012 lib/asm-tree-3.2.jar
 33094 Mon Mar 05 13:13:40 CST 2012 lib/asm-commons-3.2.jar
 36551 Mon Mar 05 13:13:40 CST 2012 lib/asm-util-3.2.jar
 17985 Mon Mar 05 13:13:40 CST 2012 lib/asm-analysis-3.2.jar
Breather answered 12/3, 2012 at 16:42 Comment(1)
Ok, I've done what is described here but I'm still getting Exception in thread "main" java.lang.NoClassDefFoundError: com/rabbitmq/client/ConnectionFactory. Should I setup classpath somehow?Downcomer
S
7

Below code could be tried. It depends on the jar task and is of Type Jar

task createJobJar(dependsOn:jar,type:Jar) {
    manifest {
        attributes(
                "Implementation-Title": 'Job '
                ,"Implementation-Version": version
        )
    }
    classifier 'job'
    destinationDir new File("$buildDir")
    into('libs'){
         from configurations.compile
    }
    into('classes'){
        from "$buildDir/classes"
    }
    into('resources'){
        from "$projectDir/src/main/resources"
    }
    into('scripts'){
        from "$projectDir/src/main/scripts"
    }
}

The above code would pack different content inside different directories. Tested on gradle 2.2

Sharronsharyl answered 18/12, 2014 at 16:20 Comment(0)
R
6

I needed to the same thing you asked, and used this method. you may not need a custom configuration declaration, but i needed to separate the locally used jar files from those declared in a super-build file.

configurations{
    //declare custom config if necessary, otherwise just use compile
    myLibs
}
dependencies {
    //add lib/*.jar files to myLibs
    myLibs fileTree(dir: 'lib', include: '*.jar')
    compile {
        //set compile configuration to extend from myLibs
        extendsFrom myLibs
    }
}
// task to copy libs to output/lib dir
task copyToLib(type: Copy) {
    into "$buildDir/output/lib"
    from configurations.myLibs
}

jar {
    //include contents of output dir
    from "$buildDir/output"
    manifest {
        //...
    }
}

//set build task to depend on copyToLib
build.dependsOn(copyToLib)
Recha answered 24/5, 2011 at 2:18 Comment(0)
G
1

I had the same problem. I solved it like this:

Copy the files into the lib folder with copyToLib and reference the dependency with the Class-Path

ext.mainClass = 'test.main'

dependencies {
    compile fileTree(include: ['*.jar'], dir: 'libs')
    compile 'com.google.code.gson:gson:2.8.2'
    //....
}

jar {
    from "$buildDir/libs/lib"
    manifest {
        attributes 'Main-Class': 'test.main',
        'Class-Path': configurations.compile.collect { 'lib/'+it.getName() }.join(' ')
    }
}

task copyToLib(type: Copy) {
    into "$buildDir/libs/lib"
    from configurations.compile
}

build.dependsOn(copyToLib)
Gratitude answered 5/3, 2019 at 0:50 Comment(0)
S
0

In my case I needed to include a contents of the root project Jar into subproject Jar. So, to make it work, one can use this template:

jar{
  manifest{
    attributes 'Main-Class':'<main class>'
  }
  def conf= configurations.find {it.name.equals('compile') }
  File jar= conf.files.find {it.name.contains('<name or part of the name of produced Jar>')}

  FileTree fileTree=zipTree(jar)
  from fileTree
}

My example:

jar{
   manifest{
       attributes 'Main-Class':'alexiy.jace.Jace'
   }
   description='Make a runnable API Jar'
   def conf= configurations.find {it.name.equals('compile') }
   File tools= conf.files.find {it.name.contains('Tools')}

   FileTree fileTree=zipTree(tools)
   from fileTree
}
Selvage answered 12/4, 2017 at 16:10 Comment(0)
B
0

Here's how I managed to achieve this build setting using Gradle. This will build your app into a Jar, copy the library jars generated into the libs directory under build/libs and also configure classpath to include the jars in the created build/libs/libs directory.

 plugins {
    id 'application'
 }

 group 'org.pkg'
 version '1.0-SNAPSHOT'

 ext.mainClass = 'org.pkg.MainClass'

 repositories {
    mavenCentral()
    mavenLocal()
 }

 dependencies {
    compile fileTree(include: ['*.jar'], dir: 'libs')
    testCompile group: 'junit', name: 'junit', version: '4.12'

    implementation group: 'com.mchange', name: 'c3p0', version: '0.9.5.5'
 }
 
 task copyToLib(type: Copy) {
    into "$buildDir/libs/libs"
    // configurations.runtimeClasspath includes maven jars
    from configurations.runtimeClasspath 
 }

 def archiveVersion = "1.0.0"

 task uberJar(type: Jar) {
    archiveClassifier = 'uber'

    from sourceSets.main.output
    // include the copy task
    dependsOn(copyToLib)

    // use onfigurations.runtimeClasspath to collect all the jars
    manifest {
      attributes(
            'Class-Path': configurations.runtimeClasspath.collect { 'libs/' + it.getName() }.join(' '),
            'Main-Class': 'org.pkg.MainClass',
            "Implementation-Title": "Gradle",
            "Implementation-Version": archiveVersion
      )
    }
 }
Bingham answered 1/7, 2020 at 10:29 Comment(0)
S
-1
task <taskname>(type: Jar) {
    archiveName 'nameofjar.jar'
    doFirst {
    manifest {
            attributes 'Class-Path': configurations.compile.files.collect{ project.uri(it) }.join(' ')
        }
    }
}
Seriocomic answered 27/6, 2017 at 9:27 Comment(1)
A bit of an explanation about what this code does might help explain some of the specific bits?Fahey

© 2022 - 2024 — McMap. All rights reserved.