48

I got a runnable jar with this build.gradle

    apply plugin: 'java'
    apply plugin: 'application'

    manifest.mainAttributes("Main-Class" : "com.test.HelloWorld")

    repositories {
        mavenCentral()
    }

    dependencies {
        compile (
            'commons-codec:commons-codec:1.6',
            'commons-logging:commons-logging:1.1.1',
            'org.apache.httpcomponents:httpclient:4.2.1',
            'org.apache.httpcomponents:httpclient:4.2.1',
            'org.apache.httpcomponents:httpcore:4.2.1',
            'org.apache.httpcomponents:httpmime:4.2.1',
            'ch.qos.logback:logback-classic:1.0.6',
            'ch.qos.logback:logback-core:1.0.6',
            'org.slf4j:slf4j-api:1.6.0',
            'junit:junit:4.+'
        )
    }

but it run failed, because the dependencies jars can't find.

and then I add this code:

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

but nothing change. I can't find the folder output/libs.

how can I copy the dependencies libs jars to a specified folder or path?

Sergey
  • 3,253
  • 2
  • 33
  • 55
jychan
  • 991
  • 2
  • 10
  • 14

8 Answers8

46

Add:

build.dependsOn(copyToLib)

When gradle build runs, Gradle builds tasks and whatever tasks depend on it (declared by dependsOn). Without setting build.dependsOn(copyToLib), Gradle will not associate the copy task with the build task.

So:

apply plugin: 'java'
apply plugin: 'application'

manifest.mainAttributes('Main-Class': 'com.test.HelloWorld')

repositories {
    mavenCentral()
}

dependencies {
    compile (
        'commons-codec:commons-codec:1.6',
        'commons-logging:commons-logging:1.1.1',
        'org.apache.httpcomponents:httpclient:4.2.1',
        'org.apache.httpcomponents:httpclient:4.2.1',
        'org.apache.httpcomponents:httpcore:4.2.1',
        'org.apache.httpcomponents:httpmime:4.2.1',
        'ch.qos.logback:logback-classic:1.0.6',
        'ch.qos.logback:logback-core:1.0.6',
        'org.slf4j:slf4j-api:1.6.0',
        'junit:junit:4.+'
    )
}

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

build.dependsOn(copyToLib)
Jay Taylor
  • 13,185
  • 11
  • 60
  • 85
xielingyun
  • 780
  • 9
  • 17
  • In SonarQube analysis, during Javacode AST scan, I was getting ERROR/WARN - Class xx.yy.zz not found. To fix that, I had to set "sonar.java.libraries" which contains all the jar (dependencies) required during compile, testCompile, runtime. I added "from configurations.compile from configurations.testCompile from configurations.runtime". I got all the jars in "build/dependent-jars" folder. Setting sonar.java.libraries=build/dependent-jars/*.jar I'm not getting error. Thanks, as gradle maintains its cache outside of workspace but using this code I was able to get the .jar in build folder. – AKS Aug 21 '15 at 17:19
18

I find the application plugin way too cumbersome and too verbose in its output. Here's how I finally got a setup I was happy with, i.e., create a distribution zip file with dependency jars in subdirectory /lib and add all dependencies to Class-Path entry in the manifest file:

apply plugin: 'java'
apply plugin: 'java-library-distribution'

repositories {
    mavenCentral()
}

dependencies {
    compile 'org.apache.commons:commons-lang3:3.3.2'
}

// Task "distZip" added by plugin "java-library-distribution":
distZip.shouldRunAfter(build)

jar {
    // Keep jar clean:
    exclude 'META-INF/*.SF', 'META-INF/*.DSA', 'META-INF/*.RSA', 'META-INF/*.MF'

    manifest {
        attributes 'Main-Class': 'com.somepackage.MainClass',
                   'Class-Path': configurations.runtime.files.collect { "lib/$it.name" }.join(' ')
    }
    // How-to add class path:
    //     http://stackoverflow.com/questions/22659463/add-classpath-in-manifest-using-gradle
    //     https://gist.github.com/simon04/6865179
}

Hosted as a gist here.

The result can be found in build/distributions and the unzipped contents look like this:

lib/commons-lang3-3.3.2.jar
MyJarFile.jar

Contents of MyJarFile.jar#META-INF/MANIFEST.mf:

Manifest-Version: 1.0
Main-Class: com.somepackage.MainClass
Class-Path: lib/commons-lang3-3.3.2.jar

Martin Andersson
  • 18,072
  • 9
  • 87
  • 115
8

Since Gradle 6.0 it is:

tasks {
    val deps by registering(Copy::class) {
        from(configurations.runtimeClasspath)
        into("build/deps")
    }
}
Nikita Tukkel
  • 1,975
  • 1
  • 9
  • 15
2

The problem with all the previous answers is that they only collect dependencies from one configuration. To get ALL of the dependencies, you should use this:

task saveDependencies(type: Copy){
    configurations.each {
        if (it.isCanBeResolved())
            from it into "gradle_dependencies"
    }
    from buildscript.configurations.classpath into "gradle_dependencies"
}
Fizz Areh
  • 87
  • 7
  • when would you want to include compile time dependencies in a jar though? – Brad Mace Mar 14 '22 at 13:55
  • 2
    @BradMace I dont include the dependencies into a jar. I simply copy them to a separate folder. You would want to do this when, for example, you have a bunch of remote dependencies and you are afraid of some repositories going offline, so you make a local copy of everything. – Fizz Areh Mar 19 '22 at 14:49
1

The application plugin requires you to set the main class name like this:

mainClassName = "com.test.HelloWorld"

You will need to add that to your build script. Keep in mind that if you try to run your application with the java command you will also need to set the classpath with -cp.

The application plugin simplifies this process by providing the task distZip. If you run that task you a full distribution is created for you under build/distributions. The distribution contains start scripts and all dependencies. The generated start scripts already set the classpath for you so you don't have to deal with it anymore.

Benjamin Muschko
  • 32,442
  • 9
  • 61
  • 82
1

The java plugin can pack a jar with dependencies and there's no need for the application plugin. A task like the following would do:

task buildWithDeps(type: Jar) {
    manifest {
        attributes "Main-Class": "com.test.HelloWorld"
    }
    from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
    with jar
}
lainatnavi
  • 1,453
  • 1
  • 14
  • 22
1

As of at least Gradle 5.6.4 you'll want to do something closer to this.

dependencies {
    implementation 'my.group1:my-module1:0.0.1'
    implementation 'my.group2:my-module2:0.0.1'
}

jar {
    from {
        configurations.compileClasspath.filter { it.exists() }.collect { it.isDirectory() ? it : zipTree(it) }
    }
}
Jason Slobotski
  • 1,386
  • 14
  • 18
0

For Gradle 7.4 with Groovy:

configurations {
    externalLib.extendsFrom(implementation)
}

task copyLibs(type: Copy){
    from configurations.externalLib{
        into '<dest-dir-name>'

        exclude('<if any jars need to be excluded>')
    }
}
Shandilya
  • 73
  • 9