Dropwizard runnable jar with Gradle
Requirement
Build a runnable jar for a Dropwizard project from test* sources using Gradle.
- Unlike most scenarios, where the Dropwizard application code sits in the main sources directory, I had a scenario where the application lived in the test sources (example: /src/test/java)
Implementation
Approach 1 - did not work
Wanted to avoid using 3rd party plugins so built an uber jar as follows
task packageTests(type: Jar) {
manifest {
attributes 'Main-Class': 'example.MyDropwizardAppMain'
}
from {
sourceSets.test.output
}
from {
configurations.testCompile.collect {
it.isDirectory() ? it : zipTree(it)
}
}
from {
configurations.testRuntime.collect {
it.isDirectory() ? it : zipTree(it)
}
}
exclude("META-INF/*.SF")
zip64=true
archiveName "${baseName}-tests.jar"
}
Notes
- The attribute
zip64
whose value defaults to false was required to be set to true as the resulting uber jar was larger (or contained more than the allowed number of files) than what is allowed by default - The exclude attribute excluding files with
.SF
extension in the META-INF folder was required to prevent any signing issues in the resulting uber jar. Without this, errors like the following are likelyException in thread "main" java.lang.SecurityException: Invalid signature file digest for Manifest main attributes
While this approach is known to have worked in most scenarios, it didn’t work for my Dropwizard application as running the uber jar gave the following error
Could not resolve type id 'http' into a subtype of [simple type, class io.dropwizard.jetty.ConnectorFactory]
A little reading on the web suggested this is due to the invalid merging of
files in the META-INF/services
folder across all jar dependencies that get
packaged into the uber jar.
Approach 2 - using the ShadowJar plugin
Using the Shadow Jar Gradle plugin
that has an option to mergeServiceFiles()
appropriately (didn’t really care
about understanding how ‘appropriately’ is precisely defined in this context)
worked and I was able to run my Dropwizard application using the resulting uber
Jar.
Gradle build script snippets below
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.github.jengelman.gradle.plugins:shadow:2.0.0'
}
}
apply plugin: 'com.github.johnrengelman.shadow'
shadowJar {
classifier = 'tests'
from sourceSets.test.output
configurations = [project.configurations.testRuntime]
mergeServiceFiles()
manifest {
attributes 'Main-Class': 'example.MyDropwizardAppMain'
}
}
References
- http://imperceptiblethoughts.com/shadow/
- https://gist.github.com/yunspace/170efc94faa7fe974207