Fat jar built with Gradle doesn't include libraries - java

I'm trying to build a fat jar which would contain all .jar libraries included in 'libraries' folder.
Here is a snapshot of my build.gradle file:
group 'MyApp'
version '2.0'
apply plugin: 'java'
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
dependencies {
testCompile group: 'junit', name: 'junit', version: '4.12'
compile files('libraries/ojdbc7.jar')
compile files('libraries/postgresql-42.1.4.jar')
compile files('libraries/db2jcc.jar')
}
tasks.withType(Jar) {
destinationDir = file("$rootDir/target")
}
jar {
from {
configurations.compile.collect {
it.isDirectory() ? it : zipTree(it)
}
}
manifest {
attributes 'Main-Class': 'MainLauncher'
}
processResources{
exclude '*'
}
archiveName 'myapp.jar'
}
All .jar libraries are included into 'libraries' folder located in root of the project.
For some reason my code works fine in IDE, however fails to execute some tasks when run as a standalone .jar file.
When I decompress the jar, I can see all content inside root folder including libraries which fail to be found.
Is there anything I'm doing wrong?

Related

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

How to Obfuscate a fatJar with Klassmaster

I have a fat jar which is generated by using gradle script. Post the gradle script when I run the following command :-
java -jar fileName.jar
it is running the main method and things are fine. Nevertheless when I try to obfuscate this jar, the resulting jar is complaining that :-
Error: Invalid or corrupt jarfile ObfusactedTest.jar
My code is as follows:-
build.gradle:-
buildscript {
repositories {
mavenLocal()
mavenCentral()
}
dependencies {
classpath files("E:\\softs\\ZKM\\ZKMEval\\ZKM.jar") //ZKM_JAR_PATH must be set to point to your ZKM.jar
classpath 'com.zelix.gradle:plugin:1.0.0'
}
}
apply plugin: 'java'
apply plugin: 'maven'
apply plugin: 'com.zelix.gradle.plugin'
group = 'com.github.jitpack'
sourceCompatibility = 1.8 // java 8
targetCompatibility = 1.8
repositories {
mavenLocal()
mavenCentral()
}
dependencies {
compile group: 'org.apache.commons', name: 'commons-lang3', version: '3.11'
compile group: 'org.apache.commons', name: 'commons-collections4', version: '4.4'
}
jar {
manifest {
attributes "Main-Class": "com.github.jitpack.Hello"
}
zip64 = true
from {
configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
}
}
zkmSetting {
scriptName = "Obfuscate.txt" //Must be set to point to the ZKM Script to execute.
}
Obfuscate.txt:-
print "Obfuscating fatJar.....";
classpath
"C:\Program Files\Java\jdk-10.0.2\lib\jrt-fs.jar"
".\obfuscateFatJar.jar";
open ".\obfuscateFatJar.jar" {"*.class"};
exclude org.apache.commons.*.*;
exclude com.github.jitpack.Hello.*;
obfuscate keepInnerClassInfo=false
keepGenericsInfo=true
exceptionObfuscation=heavy
encryptStringLiterals=flowObfuscate;
saveAll archiveCompression=asIs
deleteEmptyDirectories=true
deleteXMLComments=false
"ObfusactedTest.jar";
By the way Hello.java has got the main method.
Your ZKM Script "open" statement specifies the {"*.class"} file filter. So you are filtering out ALL non-class files including your MANIFEST.MF. See https://www.zelix.com/klassmaster/docs/openStatement.html#filter.
A missing MANIFEST.MF will give you a "Invalid or corrupt jarfile" error. Note that your Zelix KlassMaster log file will contain messages like the following.
MESSAGE: Filtering out path 'obfuscateFatJar.jar!META-INF/MANIFEST.MF' because it does not match specified filter '{".class"}>' (D)*
You can work around this by not using a file filter (the safest option in this case) or by broadening your file filter to include other file types. E.g. {".class" || ".MF"}
Update the filter in the class path. The code looks like this now. Works like a charm.
execute "del ObfusactedTest.jar";
classpath
"C:\Program Files\Java\jdk-10.0.2\lib\jrt-fs.jar"
".\obfuscateFatJar.jar";
open ".\obfuscateFatJar.jar" {"*.class" || "*.MF"};
exclude org.apache.commons.*.*;
obfuscate keepInnerClassInfo=false
keepGenericsInfo=true
exceptionObfuscation=heavy
encryptStringLiterals=flowObfuscate;
saveAll archiveCompression=asIs
deleteEmptyDirectories=true
deleteXMLComments=false
"ObfusactedTest.jar";

Use local jar as a dependency in my Gradle Java project

I have a local jar file named mylib.jar. I want to used it as a dependency in my Gradle Java project.
This is what I tried:
I created a libs/ folder under project root. I put the jar file under libs/ folder.
MyProject
->libs/mylib.jar
->build.gradle
->src/...
In my build.gradle:
apply plugin: 'java-library'
group 'com.my.app'
version '1.0-SNAPSHOT'
sourceCompatibility = 1.8
repositories {
mavenCentral()
flatDir {
dirs 'libs'
}
}
dependencies {
testCompile group: 'junit', name: 'junit', version: '4.12'
api files('libs/mylib.jar')
}
But I can't access the public classes defined in mylib.jar in my project code. Why?
===== More information =====
The content of my jar:
mylib.jar
> com.my.jar.package
>ClassFromJar.class
Here is how I use the jar:
// Compilation error: Cannot resolve symobl 'ClassFromJar'
import com.my.jar.package.ClassFromJar;
public class MyEntryPoint {
// Compilation error: Cannot resolve symbol 'ClassFromJar'
ClassFromJar instance = new ClassFromJar();
}
Similar answers suggesting
Local dir
Add next to your module gradle (Not the app gradle file):
repositories {
flatDir {
dirs 'libs'
}
}
Relative path:
dependencies {
implementation files('libs/mylib.jar')
}
Use compile fileTree:
compile fileTree(dir: 'libs', include: 'mylib.jar')
A flatDir repository is only required for *.aar(which is an Android specific library format, completely irrelevant to the given context). implementation and api affect the visibility, but these are also Android DSL specific). In a common Java module, it can be referenced alike this:
dependencies {
compile fileTree(include: ["*.jar"], dir: "libs")
}
And make sure to drop the *.jar into the correct one libs directory, inside the module.
I thinks you should use in dependency declaration compile name: 'mylib' in this case flatDir will search for mylib.jar.
You could try following build.gradle (it works in my project):
plugins {
id 'java'
}
apply plugin: 'java-library'
group 'dependency'
version '1.0-SNAPSHOT'
sourceCompatibility = 1.8
repositories {
mavenCentral()
flatDir {
dirs 'libs'
}
}
dependencies {
testCompile group: 'junit', name: 'junit', version: '4.12'
compile name: 'mylib'
}
Just in case:
1 - compiler must have access to lib directory and jar
example:
javac -cp .;lib\* *.java
2 - ALSO import must be mentioned in java file
example in your java add
import static org.lwjgl.glfw.GLFW.*;

Gradle building old version of code

I'm trying to build a fat jar with gradle but every time I do I get a really old version of the program. Running the program from main directly in IntelliJ works fine so it is something with the gradle build itself that is not working. When i check the jar in (project path)/build/libs the date and time of the file has changed so it did indeed build but when i start it i get a month old build. I suspect there might be some cache that is causing this but i do not know where that is located.
build.gradle
version '1.0.2'
apply plugin: 'java'
repositories {
mavenCentral()
}
task fatJar(type: Jar) {
manifest {
attributes 'Implementation-Title': 'Example',
'Implementation-Version': version,
'Main-Class': 'com.example.Main'
}
baseName = project.name
from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
with jar
}
jar {
manifest {
attributes(
'Main-Class': 'com.example.Main',
)
}
}
dependencies {
compile 'com.intellij:forms_rt:6.0.5'
compile project(':common')
testCompile group: 'junit', name: 'junit', version: '4.11'
sourceCompatibility = 1.7
targetCompatibility = 1.7
}
settings.gradle
rootProject.name = 'example'
include ':common'
project(':common').projectDir = new File(settingsDir, '../common')
Command
./gradlew fatjar
Well, I discovered the problem and it was a combination of things. The only thing that was actually outdated was the form ui. The reason for this was that IntelliJ started using binary class files for the forms instead of java source files.
To fix it go to settings then editor and after that GUI designer. Press Java source code instead of binary class files. Regenerate the design (might have to delete the generated code and run it again). Then build it with gradle, it should now work.

Add to subproject to gradle jar

How can I add a subproject referenced using project(':api') to the jar gradle builds?
This is the build.gradle of my main project. The subproject is includes as git submodule and has a similar buildscript.
apply plugin: 'java'
sourceCompatibility = 1.5
version = '1.0'
jar {
manifest {
attributes('Main-Class': '..........')
}
}
repositories {
mavenCentral()
}
dependencies {
compile files('libs/jfxrt.jar')
compile project(':api')
testCompile group: 'junit', name: 'junit', version: '4.11'
}
I figured it out on my own.
Include the source of a subproject in the main jar:
sourceSets {
main {
java {
srcDir project(':api').file('src/main/java')
}
}
}
Including the classes of a jar in the main jar:
jar {
from zipTree('libs/abc.jar')
}
Try to add classpath to your manifest file. You need to have directory (example below uses "lib") to keep jar files on which your project depends.
Try modifying your "jar" block in gradle build to something like this. I have some addition properties just for demonstration. But the important one is Class-Path
jar {
manifest.attributes(
'Class-Path': lib/api.jar
'Built-By': System.getProperty('user.name'),
'Built-JDK': System.getProperty('java.version'),
'Built-OS': System.getProperty('os.name'),
'Built-DATE': buildDate,
)
}
I hope it helps to fix your issue.
In the simplest case, a fat Jar can be created as follows:
main/build.gradle:
jar {
from configurations.runtime
}
There are other, more robust solutions, such as the gradle-one-jar plugin for "main" method style applications.

Categories

Resources