Background
For a long time we have been using compileOnly
for production and implementation
for development (for IDE support). We use ShadowJar
plugin to generate the application jar file. All the dependencies are stored in a lib
directory and linked in the classpath.
The reason behind that way of working is time. Its just faster to compile and to deploy. For example, one of our applications takes like 5 minutes to compile when using implementation
in the project dependencies against few seconds when using compileOnly
. Then, the resulting file when using implementation
is about 800MB, while its under 1MB when using compileOnly
(as all the dependencies are just copied to a directory without creating a “fat jar”). Using rsync
to the target server is much more convenient than copying each time a 800MB file (specially under slow networks).
Problem Description
One of our libraries uses implementation
for those dependencies which are no directly required by the application. For example, the library wraps gson library but it doesn’t expose any of its classes to the consumer.
The problem is that when using compileOnly
, those libraries are not copied into the lib
directory resulting in a NoClassDefFoundError
exception. That doesn’t happen when we create a “fat jar” using implementation
.
Question
Is there a way to include those libraries as well ? configuration.compileClasspath
doesn’t include those libraries. Are we doing something wrong?
build.gradle (interesting parts)
Gradle version: 7.1.1
// Using ShadowJar Plugin:
plugins {
id 'groovy'
id 'com.github.johnrengelman.shadow' version '7.0.0'
}
// Using compileOnly to reduce jar size
dependencies {
compileOnly "com.example.library:module:1.0.0"
... many more ...
}
// Copying all the dependencies into "lib" directory
task copyRuntimeLibs(type: Copy) {
into "lib"
from configurations.compileClasspath
}
// Basic ShadowJar configuration:
shadowJar {
archiveBaseName.set(project.name)
archiveVersion.set(project.version.toString())
archiveClassifier.set("linux-x86_64")
zip64 = true
shadowJar.finalizedBy copyRuntimeLibs
}
// Linking all the libraries under "lib" to the class path:
jar {
from configurations.runtimeClasspath.collect { zipTree it }
manifest {
attributes(
'Implementation-Version': archiveVersion,
'Main-Class': "${systemMainClass}",
"Class-Path": configurations.compileClasspath.collect { 'lib/' + it.name }.join(' ')
)
}
exclude 'META-INF/*.RSA', 'META-INF/*.DSA', 'META-INF/*.SF'
}