I am new to Gradle and to shadow jar (Gradle version of Maven's Shade plugin). I am building a fat jar, in which I want to merge service files (that's why I am using shadow jar in the first place).
According to the documentation shadowJar task inherits from gradle Jar task. So, one would assume that it will work exactly as a jar task.
Here is the snippet of the jar task:
jar {
zip64 true
from { configurations.runtime.collect { it.isDirectory() ? it : zipTree(it) }
}
As a result, it produces a fat jar with all the dependencies exploded, what is anticipated. When I change task name from jar to shadowJar, like below:
shadowJar {
zip64 true
from { configurations.runtime.collect { it.isDirectory() ? it : zipTree(it) }
}
I get a jar file that contains only files from the current project, dependencies are excluded. Why is this happening?
You don't need to define the from... part. The plugin will include all dependencies automatically.
Related
I use the shadow jar plugin (https://github.com/johnrengelman/shadow) to create an extra jar file with all my dependencies packaged inside. I also would like to keep the default generated jar that has only my code & resources. This is pretty simple and straightforward until it comes to publishing the jars.
As my shadow jar has all its deps inside, its pom file is not a priority for me in terms of publishing. However if I follow the instructions laid out in the shadowJar plugin documentation (https://imperceptiblethoughts.com/shadow/publishing/#publishing-with-maven-publish-plugin)
publishing {
publications {
shadow(MavenPublication) { publication ->
project.shadow.component(publication)
}
}
I end up with two different pom files (one for the regular jar file and one for the shadow jar) published to the same URL with one overriding the other. This behavior causes customers to download the default jar but without any dependencies in the pom file.
I tried many ways to disable shadowJar pom file but without any success. How do I get it to work?
Eventually I just ignored the instructions in the plugin's documentation and published the shadow jar just like I publish my sources jar:
Simplest way to do this for a single project is:
publishing {
publications {
Library(MavenPublication) {
from project.components.java
artifact tasks.sourceJar
artifact tasks.shadowJar
}
}
}
If you have multiple projects (not all having shadowJar plugin applied) and want to add this logic in the root project, you can do this:
subprojects {
afterEvaluate {
publishing {
publications {
Library(MavenPublication) {
from project.components.java
artifact tasks.sourceJar
if (project.tasks.findByName("shadowJar") != null) {
artifact tasks.shadowJar
}
}
}
}
}
}
There are lots of repeated answers on how to exclude an individual file from a fatJar. Typically, the file is excluded are in META-INF and they are excluded either because of a filename conflict, or because it is a signature copied from a dependency libarar Jar file which isn't valid for the newly created Jar file.
Example for maven:
How can I tell which signed jar is causing maven-shade-plugin to fail?
Example for gradle:
Removing Jar Signatures in Gradle Build
These solutions, however, only removed the offending file individually.
How can we make a fatJar with a specific dependency library (not individual files in that library) excluded?
For example, in question 36226033, it's easy to exclude the signature copied over from BouncyCastle, but is there a way to exclude the dependency library bcprov-jdk15on-*.jar entirely, so that the user must have the library available in order to execute the generated fat Jar?
This is proven not working:
task fatJar(type: Jar) {
manifest {
attributes 'Implementation-Title': 'Gradle Jar File Example',
'Implementation-Version': version,
'Main-Class': 'com.alphawallet.scripttool.Main'
}
baseName = project.name + '-all'
from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
exclude('**/bcprov-jdk15on-1.62.jar')
with jar
}
With exclude('**/bcprov-jdk15on-1.62.jar'), the content of that jar file is still copied over to the fat jar generated.
Thanks. The motivation is to ship my Java application to systems that provides their own security library BouncyCastle (e.g. Debian Linux), instead of embeding an unsigned copy of that security library.
I don't know how excludes and includes works, but I would expect that these configurations work on a class file level, because that what the jar is working on.
It's not working on jars.
I would go for this solution:
task fatJar(type: Jar) {
manifest {
attributes 'Implementation-Title': 'Gradle Jar File Example',
'Implementation-Version': version,
'Main-Class': 'com.alphawallet.scripttool.Main'
}
baseName = project.name + '-all'
configurations.compile.findAll { file ->
// file is of type java.io.File
// when true, jar file is unziped and added
file.name != "bcprov-jdk15on-1.62.jar"
}.sort { it.name }
.collect { file ->
logger.info("Including file: ${file.name}")
file.isDirectory() ? file : zipTree(file)
}
with jar
}
In my Gradle project, I define an additional sourceSet.
sourceSets {
sample {
java {
srcDir 'sample/java'
}
compileClasspath += sourceSets.main.output + sourceSets.main.compileClasspath
}
}
I then add a task:
task sampleJar(type: Jar) {
classifier 'sample'
from sourceSets.sample.output
}
artifacts {
archives sampleJar
}
If I do > gradle build the additional jar file builds from the additional source set. However, if I do > gradle jar, it doesn't. any reason why?
When I go through the output messages, I see:
gradle build has sampleJar in the Tasks to be executed:
but
gradle jar doesn't.
But unsure as to why?
Because jar is just the task that assembles the main jar file.
build, on the other hand, is the top-level life-cycle task, which depends on assemble. And assemble is documented as
Depends on: jar, and all other tasks that create artifacts attached to the archives configuration.
Since your sampleJar pecisely creates an artifact attached to the archives configuration, assemble, and thus build depends on it.
I have a Gradle project and I create a regular classes jar, and also a javadoc and sources jar.
In all three I need to include a META-INF folder that includes a LICENSE and NOTICE file.
I have this folder with files under src/main/resources/
the classes jar and the sources jar work correctly but I need to also get them added to the javadoc jar.
How can I fix the javadocJar task to include META-INF folder?
// custom tasks for creating source/javadoc jars
task sourcesJar(type: Jar, dependsOn:classes) {
classifier = 'sources'
from sourceSets.main.allSource
}
task javadocJar(type: Jar, dependsOn:javadoc) {
classifier = 'javadoc'
from javadoc.destinationDir
}
// add javadoc/source jar tasks as artifacts
artifacts {
archives sourcesJar
archives javadocJar
}
I did get what I needed by adding a copy task but it would be good if I could select just the META-INF directory in case I add more directories under resources.
// custom tasks for creating source/javadoc jars
task sourcesJar(type: Jar, dependsOn:classes) {
classifier = 'sources'
from sourceSets.main.allSource
}
task copyResources(type: Copy, dependsOn:javadoc) {
into javadoc.destinationDir
from sourceSets.main.resources
}
task javadocJar(type: Jar, dependsOn:copyResources) {
classifier = 'javadoc'
from javadoc.destinationDir
}
I would like to output a jar which internally contains my dependency jar but overrides a particular file in the dependency jar with my own. I am using gradle build. Can someone help me with this? The task which build jar for me:
jar {
archiveName "JarName-${version}.jar"
dependsOn configurations.runtime
from {
(configurations.runtime - configurations.provided).collect {
it.isDirectory() ? it : zipTree(it)
}
}
}
Well I actually stopped duplicating the file by including the following strategy:
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
It seems like my changes becomes a part of the output jar before they are being overridden by the file in my dependency jar. So, restricting duplicacy helped in resolving the issue.