How to build jar file with gradle with dependencies - java

I'm building a jar file with Gradle. This jar file is being used as a library in another project. But when the project tries to use the jar file, a ClassNotFoundException is returned.
Caused by: java.lang.NoClassDefFoundError: com/auth0/jwt/JWT
I've included the jwt library in the gradle file building the jar:
compile group: 'com.auth0', name: 'java-jwt', version: '3.4.0'
The project using the jar can't seem to find this jar dependency in the jar.
I built the jar with the gradle command:
task fatJar(type: Jar) {
manifest {
attributes 'Implementation-Title': 'Jar File creation',
'Implementation-Version': version,
'Main-Class': 'com.group.me.name.MyJarClass'
}
baseName = project.name + '-all'
from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
with jar
exclude 'META-INF/*.RSA', 'META-INF/*.SF','META-INF/*.DSA'
}
How do I include the missing dependency in the jar?

You, generally, should not pack the dependencies inside a published JAR. It's better to declare them as dependencies in pom.xml and let the user of you JAR fetch them. It's just a good practice that should be enough.
If it's not enough, use Gradle Shadow:
plugins {
id 'com.github.johnrengelman.shadow' version '4.0.2'
}
Fat JAR is produced with shadowJar task in this case. Publishing is easy as well:
publishing {
publications {
shadow(MavenPublication) { publication ->
project.shadow.component(publication)
}
}
repositories {
maven {
url "http://your.repo"
}
}
}

Related

How to manage external dependencies of a Gradle Plugin

Gradle Version: 1.12/2.0 (restricted due to Org policies)
JDK: 1.8
I have created a custom gradle plugin that performs some installation using code that has been defined in another sub-project of our source-code. The build.gradle for the plugin is
dependencies {
compile project(path: ':installlib', configuration: 'libConfig')
compile project(path: ':tools', configuration: 'toolConfig')
}
jar {
from {
// LINE#1 source-code of plugin
sourceSets.main.output
zip64 = true
// LINE#2 dependencies
configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
}
baseName = 'myCustomPlugin'
version = '1.0'
destinationDir = new File(project.libDir)
}
The above plugin is consumed as follows - consumer.gradle
buildscript {
repositories { flatDir name: 'libs', dirs: System.env.CODESOURCE + '/lib/')
dependencies {
classpath: ':myCustomPlugin:1.0'
}
}
apply plugin: 'java'
apply plugin: 'myCustomPlugin'
...
...
//rest of the items of this gradle
Case-A
If I run this, I hit > Plugin with id 'myCustomPlugin' not found.
NOTE: I have META-INF/gradle-plugins/myCustomPlugin.properties created correctly with implementation-class pointing to my plugin code and this works fine if I don't get into creating the fat/uber-jar business and just include the sourceSets.main.output statement in my jar task. But since our entire project depends on file based artifacts, I am attempting to create a fat/uber-jar and that's where I start running into these issues.
Case-B
If I move the LINE#2 above the LINE#1, which looks like -
from {
// LINE#2 dependencies
configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
// LINE#1 source-code of plugin
sourceSets.main.output
zip64 = true
}
If I run this, I hit ClassNotFoundException for one of the classes coming from the project 'installlib'. I can see the *.class file in the uber jar created but even then the class loader complains about this class.
Could anyone provide some pointers on how to resolve this ? The uber/fat jar creation (or the way I am doing it) is not helping with the plugin-source-code and dependencies of the plugin.
If not a fat jar, could anyone provide some inputs on how to resolve the dependencies in the buildscript of the consuming gradle ?

Gradle task to create fat runnable jar

I have a java application with Main class which has dependencies to couple of other library jars. I need to create a runnable jar in gradle with all dependant libraries copied to the jar. The gradle plugin "application" or "java" does not provide this. I am using latest gradle version 6.7
I could achieve this by creating a task which does the following things
Update manifest file with the Main-Class attributes
Copy all compile time dependencies to the jar task
plugins {
id 'application'
}
repositories {
mavenCentral()
//jcenter()
}
dependencies {
compile group: 'org.json', name: 'json', version: '20200518'
testImplementation 'junit:junit:4.13'
implementation 'com.google.guava:guava:29.0-jre'
}
task fatJar(type: Jar) {
manifest {
attributes 'Main-Class': 'com.example.gradle.App'
}
from {
configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
} with jar
}
More details can be read in this article A simple java project with Gradle

creating fatjar from obsufucated jar and library jar depedencies?

I have a a fatjar, which is a deployable jar with main method defined, and which depedencies are copied via gradle.
This works fine.
I want to obsufucate/encrypt my jar.
Using proguard I can obsufucate myJar, and specify libraryjars. How do I get a farJar created from the obsufucated jar and its dependencies ?
So far I can only obsufucate the original jar, not obsufucate and bundle as fat jar.
task fatJar(type: Jar) {
manifest {
attributes 'Implementation-Title': 'Metriculous',
'Implementation-Version': version,
'Main-Class': 'au.com.metriculous.MetriculousServer'
}
baseName = project.name + '-all'
from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
with jar
}
my proguard task looks pretty much the same as the samples, the library jars don't get added to jar as fatJar. And I don't want to define lots of rules for not obsufucating injars, which I could do if I simply obsufucate the whole fatjar ?

Want to copy .ebextensions (AWS Beanstalk) directory in repo into the root directory of a Java jar file using Gradle

I have a Spring Boot project, and I need to copy the .ebextensions folder from within my repo into the ROOT(top-level) folder of my jar file using Gradle. If it's not in the root directory of the jar file, I noticed that AWS Beanstalk will not pick up the nginx conf file under the .ebextensions folder.
i.e. this folder is currently here in the repo :
src
build.gradle
gradlew.bat
gradlew
build
README
.ebextensions
In my build.gradle, I have this code :
jar {
from('.')
into("./.")
include '.ebextensions/**'
}
But, I find out that the .ebextensions folder will end up under BOOT-INF/classes/ in the jar file. And it will also wipe all other class files that would otherwise be under BOOT-INF/classes/ too!
How do I get my directory on the same level as BOOT-INF? i.e. like this :
.
..
BOOT-INF
WEB-INF
.ebextensions
<Rest of the source files here>
Thanks!
P.S. I have also tried another solution below but it doesn't work either :
task copyEbExtensions(type: Copy) {
from '.'
into { getDestDir() }
include '.ebextensions'
}
P.S.#2 Also, this is my build.gradle in case this is helpful :
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:1.5.7.RELEASE")
}
}
apply plugin: 'java'
apply plugin: 'idea'
apply plugin: 'org.springframework.boot'
jar {
baseName = 'oneyearafter'
version = '0.1.26'
}
task copyEbExtensions(type: Copy) {
from '.'
into { getDestDir() }
include '.ebextensions'
}
task wrapper(type: Wrapper) {
gradleVersion = '2.0'
}
repositories {
mavenCentral()
}
sourceCompatibility = 1.8
targetCompatibility = 1.8
dependencies {
compile("org.springframework.boot:spring-boot-devtools")
compile("org.springframework.boot:spring-boot-starter-web")
// tag::actuator[]
compile("org.springframework.boot:spring-boot-starter-actuator")
// end::actuator[]
// tag::tests[]
compile("org.thymeleaf:thymeleaf-spring4")
compile("org.springframework.boot:spring-boot-starter-security")
// JPA Data (We are going to use Repositories, Entities, Hibernate, etc...)
compile 'org.springframework.boot:spring-boot-starter-data-jpa'
// Use MySQL Connector-J
compile 'mysql:mysql-connector-java'
}
bootRun {
addResources = true
}
Here is my custom gradle function to build jar file. Run task compileRunableJarFile to compile jar file.
apply plugin: 'java'
sourceSets {
main {
java {
srcDir 'src/java'
}
resources {
srcDir 'src'
exclude 'src/java/**/*'
}
}
}
compileJava.dependsOn(processResources)
jar {
duplicatesStrategy = 'exclude'
manifest {
attributes 'Implementation-Title': title,
'Implementation-Version': version,
'Implementation-Vendor': vendor,
'Created-By': creator,
'Main-Class': mainClass,
'Manifest-Version': version,
'Manifest-Title': title,
'Application-Name': title,
'JPA-PersistenceUnits': persistenceUnit
}
}
//create a single Jar with all dependencies
task compileRunableJarFile(type: Jar, description: 'to create runable JAR.', group: 'compile') {
manifest {
attributes 'Implementation-Title': title,
'Implementation-Version': version,
'Implementation-Vendor': vendor,
'Created-By': creator,
'Main-Class': mainClass,
'Manifest-Version': version,
'Manifest-Title': title,
'Application-Name': title,
'JPA-PersistenceUnits': persistenceUnit
}
baseName = 'app_name_prefix-' + getCurrentTime()
from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
with jar
}

Gradle: Zipping Multi-project dependencies into application JAR file?

In a build.gradle script, I would perform the following task to include dependencies into a runnable application JAR file.
jar {
manifest {
attributes(
'Class-Path': configurations.compile.collect { it.getName() }.join(' '),
'Main-Class': 'org.somepackage.MyMainClass'
)
}
from configurations.compile.collect { entry -> zipTree(entry) }
}
However, in multi-project setups I was missing some dependencies in the JAR file. I ultimately discovered any dependencies specified in other project build.gradle scripts were not being included, unless the parent project had those dependencies too.
For example, Project A depends on Project B. Project B uses Google Guava. When I deployed Project A to a runnable JAR file, Google Guava would not be included and there would be runtime errors. If Project A redundantly specified Google Guava in its build.gradle script, then it runs just fine.
How can I modify my jar task above to include dependencies in multi-project setups?
I got some ideas from this post that seemed to work.
jar {
manifest {
attributes(
'Main-Class': 'com.swa.rm.pricing.reporting.ux.SaleMxReportingUI'
)
}
}
task fatJar(type: Jar) {
manifest.from jar.manifest
classifier = 'all'
from {
configurations.runtime.collect { it.isDirectory() ? it : zipTree(it) }
} {
exclude "META-INF/*.SF"
exclude "META-INF/*.DSA"
exclude "META-INF/*.RSA"
}
with jar
}

Categories

Resources