I have Gradle JAR (Main) project. I have other commons-io jars (dependent) that I would like to package them with the Main JAR. I tried below, but when I decompile Main JAR, I see all the dependent JARS inside libs folder with .jar extension.
jar {
from("$projectDir") {
include 'libs/**'
}
}
What I want is the class files from all the dependent JARs into Main JAR. I am doing this because the Main JAR is going to be used by multiple projects. So that way, I do not have to include all the dependent JARs.
Thanks
As far as I know You cannot pack other jars into single jar just like that. What You need to do is to extract all the jars and pack the content into single file.
Following piece of code prepares such jar for declared dependencies
apply plugin: 'java'
repositories {
mavenCentral()
}
dependencies {
compile 'com.google.guava:guava:16.0.1'
compile 'com.google.inject:guice:3.0'
}
task fatJar(type: Jar, dependsOn: jar) {
baseName = project.name + '-fat'
deps = configurations.runtime.collect { it.isDirectory() ? it : zipTree(it) }
from(deps) {
exclude 'META-INF/MANIFEST.MF'
}
}
use this.
into(libForderName){
from {
configurations.compile.collect {
it.isDirectory() ? it : it.getAbsoluteFile()
}
}
}
Related
The typical answer for uberjar is the following code:
build.gradle for project
manifest {
attributes("Main-Class": "main.Main" )
}
jar{
//<editor-fold defaultstate="collapsed" desc="uberjar">
//uberjar start
from(configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }) {
exclude "META-INF/*.SF"
exclude "META-INF/*.DSA"
exclude "META-INF/*.RSA"
}
//uberjar end
//</editor-fold>
}
From what I observe, this works by putting in all the jars in maven local.
How do I make it uberjar ONLY the dependencies, or only the dependencies that I choose?
You can use include or exclude configuration(or both if it suits your needs) to specify which packages you want in your uberjar.
Example:
task customJar(type: Jar) {
.....
exclude('com/somePack/excludePack1/**')
exclude('com/somePack/excludePack2/**')
include('com/somePack/**')
from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
with jar
}
// this example will include only packages with com/somePack/
// since exclude configuration specifies com/somePack/excludePack1/ and
// com/somePack/excludePack2/ packages to be excluded.
// any other packages under com/somePack/ will be included in the jar.
If you use include it will only contain the packages that matches include definitions.
If you use exclude, it wont containt any packages that mathces exlude defitions.
You can choose to exclude your own source codes like this. I suggest creating a custom jar task and executing this task for this kind of things. (Ex: gradle yourJarTaskName)
I am trying to create a jar of jars without unzipping class files from each jar. Unfortunately shadowJar unzip's all jars and resulting jars contain directories instead of jars.
My build.gradle file is:
apply plugin: 'com.github.johnrengelman.shadow'
dependencies {
compile("ldapjdk:ldapjdk:1.0"){
transitive = false
}
compile("support:activemq-core:5.3.1"){
transitive = false
}
compile("support:concurrent:0.0"){
transitive = false
}
compile("dom4j:dom4j:${dom4j_version}"){
transitive = false
}
compile("commons-lang:commons-lang:${commons_lang_version}") {
transitive = false
}
}
task copyRuntimeLibs(type: Copy) {
from(project(':server').configurations.runtime)
include 'commons-lang2*'
include 'ldapjdk*'
include 'dom4j*'
include 'concurrent*'
}
task copyFiles(dependsOn: [copyRuntimeLibs])
task copyToLib( type: Copy ) {
into "$buildDir/lib"
from configurations.runtime
}
jar { dependsOn copyToLib }
shadowJar {
zip64 true
baseName = "service"
from("$buildDir/lib") {
include '**'
}
}
I've tried from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }. This also extracts classes, MANIFEST, etc.
Is there a way to not extract classes from each jar & instead make a jar of jars?
Thanks a lot.
You may want to see this GitHub issue.
https://github.com/johnrengelman/shadow/issues/111
It is actually not solved yet in the Shadow plugin, there some workarounds are shown there.
I'm trying to use gradle with proguard to obfuscate the code then generate a zip file to distribute. I'd like to use the distribution plugin, but it always includes the jar that is generated by the jar task. Is there some way to force the distribution plugin to omit the original (non-obfuscated) jar and only include the obfuscated jar? I can easily add the obfuscated jar in addition to the original, but I want to distribute the obfuscated jar instead of the original so the generated execution scripts run against the obfuscated version.
Here's my abridged build.gradle file:
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'net.sf.proguard:proguard-gradle:5.3.3'
}
}
apply plugin: 'java'
apply plugin: 'application'
task obfuscate(type: proguard.gradle.ProGuardTask) {
configuration 'proguard.txt'
injars "build/libs/${rootProject.name}.jar"
outjars "build/libs/${rootProject.name}-release.jar"
}
jar.finalizedBy(project.tasks.obfuscate)
distributions {
main {
contents {
from(obfuscate) {
into "lib"
}
from(jar) {
exclude "*.jar"
}
}
}
}
I've tried a number of things in the distributions block to try to exclude the original jar, but nothing seems to work.
Any ideas would be greatly appreciated.
This isn't the best solution, but I was able to work around the issue by renaming the jars at the end of the obfuscation step. Now, I name the original jar something like <JAR_NAME>-original.jar and I give the obfuscated jar the original jar's name. I still wish there was a better way to do it, but this seems to work.
Here is the updated, abridged build.gradle file:
import java.nio.file.Paths
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'net.sf.proguard:proguard-gradle:5.3.3'
}
}
apply plugin: 'java'
apply plugin: 'application'
def jarNameWithoutExtension = jar.archiveName.with { it.take(it.lastIndexOf(".")) }
def obfuscatedJarName = "${jarNameWithoutExtension}-release.jar"
def jarFileLocation = jar.archivePath.parent
def obfuscatedFilePath = Paths.get(jarFileLocation, obfuscatedJarName)
task obfuscate(type: proguard.gradle.ProGuardTask) {
configuration 'proguard.txt'
injars jar.archivePath
outjars obfuscatedFilePath.toString()
// Rename the original and obfuscated jars. We want the obfuscated jar to
// have the original jar's name so it will get included in the distributable
// package (generated by installDist / distZip / distTar / assembleDist).
doLast {
jar.archivePath.renameTo(Paths.get(jarFileLocation, "$jarNameWithoutExtension-original.jar").toFile())
obfuscatedFilePath.toFile().renameTo(jar.archivePath)
}
}
jar.finalizedBy(project.tasks.obfuscate)
My build uses source code from two projects: ProjectA and ProjectB, and produces JAR with classes and resources from ProjectB. I defined custom sourceSet mainProjectB which is supposed to have output in a separate directory:
sourceSets {
mainProjectB {
output.classesDir = "$buildDir/build/classes/projectB"
output.resourcesDir = "$buildDir/build/resources/projectB"
java { srcDirs = ['src/main/java']}
resources { srcDirs = ['src/main/resources']}
}
mainProjectA {
java { srcDirs = [
'../projectA/src/main/java'
]}
resources { srcDirs = [
'../projectA/src/main/resources'
]}
}
test {
java {
srcDirs = [
'../projectA/src/test/java',
'src/test/java'
]}
resources {
srcDirs = [
'../projectA/src/test/resources',
'src/test/resources'
]}
}
}
compileJava {
source sourceSets.mainProjectB.allJava
source sourceSets.mainProjectA.allJava
}
processResources {
from sourceSets.mainProjectB.resources
from sourceSets.mainProjectA.resources
}
jar {
from sourceSets.mainProjectB.output.classesDir
from sourceSets.mainProjectB.output.resourcesDir
}
Problem: custom sourceSet mainProjectB ingores specified output directories.
The directories "$buildDir/build/classes/projectB" and "$buildDir/build/resources/projectB" are not created, and as a consequence, JAR includes files from both projects (instead of ProjectB).
UPDATE:
Projects A and B have circular dependencies. That is why they have to share source code.
I would consider to use subprojects and project to achieve your goal - gradel docs . With the following approach you can get any kind of jar file depending on your build :
group 'CoreProject'
version '1.0-SNAPSHOT'
subprojects {
apply plugin: 'java'
repositories {
mavenCentral()
}
}
project (':projectA') {
}
project (':projectB') {
def generatedResources = "$buildDir"
//in case you want resources and classes to be written to custom location where
//redefined paths are relative to projectB root folder
sourceSets {
main {
output.classesDir = 'build/classes/projectB'
output.resourcesDir = 'build/resources/projectB'
}
}
dependencies {
compile project(':projectA')
}
jar {
manifest.mainAttributes(
'Main-Class': "ProjectBClass"
)
}
//To create fat Jar that will contain classes and resources from all dependencies
task fatJar(type: Jar) {
manifest.from jar.manifest
classifier = 'all'
from {
configurations.runtime.collect { it.isDirectory() ? it : zipTree(it) }
} {
exclude "ProjectAResource" //if want to exclude resources from projectA
exclude "META-INF/*.SF"
exclude "META-INF/*.DSA"
exclude "META-INF/*.RSA"
}
with jar
}
}
If you run jar task of projectB following jars will be created, each including only its own classes and resources : projectA/build/libs/projectA.jar , projectB/build/libs/projectB.jar('JAR with classes and resources from ProjectB' as you asked in your comment)
If you run farJar task of projectB the following jar file will be created that includes classes and resources from both projects and you can exclude any files patterns from projectA and projectB projects to create any final jar you like : projectB/build/libs/projectB-all.jar
Here is a screenshot of projects folders structure I created to mimic your scenario(as I understood it):
P.S. Also make sure none of the folders projectB/build and projectA/build are locked by any process and remove those handles if any, as otherwise Gradle will fail to run.
I'm trying to build a JAR from a specific package of classes so I want to exclude all the other packages from this JAR. This is what I have...
task receiverJar(type: Jar) {
baseName = "receivers"
from sourceSets.main.output
include 'com/foo/receivers/**'
exclude 'com/foo/cli/**'
exclude 'com/foo/tdl/**'
with jar
}
When I execute gradle receiverJar I still get all the other packages and classes in my JAR file.
task receiverJar(type: Jar) {
enabled = true
baseName this.name + '-receivers'
from sourceSets.main.output
manifest {
attributes 'Implementation-Version': project.version
}
include 'com/foo/tdl/**'
exclude 'com/foo/cdl/**'
}