V
V
Vlad Kosinov2014-06-29 03:45:19
Java
Vlad Kosinov, 2014-06-29 03:45:19

How to build a jar file with dependencies in a multi-module project in Gradle?

Untitled_Diagram.png
There is Module 1 and Module 2 , both depend on the Common module . Dependencies on third-party libraries in modules intersect.
Common dependencies (file common/build.gradle) :

dependencies {
    compile 'com.google.code.gson:gson:2.2.4'
    compile 'org.apache.logging.log4j:log4j-core:2.0-rc2'
}
Module-2 ( module-2/build.gradle file ):
dependencies {
    compile 'com.google.code.gson:gson:2.2.4'
    compile 'org.apache.logging.log4j:log4j-core:2.0-rc2'
    compile project(':common')
}
Module-1 ( module-1/build.gradle file ):
dependencies {
    compile 'com.google.code.gson:gson:2.2.4'
    compile 'org.apache.logging.log4j:log4j-core:2.0-rc2'
    compile 'com.google.guava:guava:17.0'     //  её нет в Common
    compile project(':common')
}

Task: create jar files for Module-1 and Module-2 with all the necessary dependencies inside, which could be run like this: java -jar module-1.jar .
First attempt: make the jar task responsible for the final file the same for all three modules:
jar {
    from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
    //настройка manifest'a опущена
}
The above method works, but the jar file module-1.jar (and module-2.jar ) gets the intersection of dependencies for Module-1 and Common twice, the total file size is:
SIZE( src_module1 + 2 (dep_module1 ∩ dep_common) + ( dep_module1 \ dep_common) )
Second attempt: exclude library files from the jar task of the Common module :
jar {
    //from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
}
As a result , only class files of the Common module get into common.jar , as a result, dependencies are archived into the module-1.jar file only once, which is already good. But a problem arises: if Common has some kind of dependency, but Module-1 does not, at the Module-1 level it will be necessary to describe all the necessary Common dependencies, which is unacceptable. Third attempt: return Common to step 1, and manually describe the contents of the resulting jar with all dependencies, excluding their intersection Example for Module-1:
jar {
    // из зависимостей добавляем только ту, которая в названияя содержит common
    from { configurations.compile.collect {  it.toString().contains("common") ? zipTree(it) : false } }
    // тут нужно подключить 'com.google.guava:guava:17.0'
}
This variant seemed more correct, but it is difficult for a syntactic description.
Question 1. How to specify as a source from for jar
task a) project module (the code in the example above is flawed);
b) third party library.
Question 2. Is there a correct solution to this problem?

Answer the question

In order to leave comments, you need to log in

2 answer(s)
K
kubashin_a, 2014-07-16
@vlkosinov

Quite recently asked a similar question...
In our project, 'module-1' and 'common' are two independent projects. Commons is published to Artifactory (or a local repository), while the pom file contains all the dependencies registered for it. When module-1 is built, both its own dependencies and those specific to common are "pulled out", and they all end up in the final jar.
3) Another difference of our project is that jar files are not unpacked, but loaded using jar-in-jar-loader.zip from eclipse (I didn’t find how to download it separately, but you can get it from eclipse like this: blog.eqlbin .ru/2012/04/runnable-jar-eclipse.html ). The final task looks something like this:

task staticJar (type: Jar, dependsOn: 'classes') {
    archiveName = 'static.jar'
    destinationDir = releaseDir
    from sourceSets.main.output
    from zipTree("${libsDir}/jar-in-jar-loader.zip")
    into ('libs') {
        from configurations.runtime
    }
    def manifestClasspath = './ ' + configurations.runtime.collect { 'libs/' + it.getName() }.join(' ')
    manifest {
        attributes(
            'Main-Class': 'org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader',
            'Rsrc-Main-Class': 'org.company.main.class',
            'Rsrc-Class-Path': manifestClasspath
        )
    }
}

A
anyd3v, 2014-06-29
@anyd3v

you can do exclude duplicate libraries in Common module

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question