Home > Blockchain >  Making a runnable big jar with gradle and shadow
Making a runnable big jar with gradle and shadow

Time:10-08

I would like to make a runnable jar for my test project with gradle. (with java -jar jajson.jar).

Here is my file tree :

-src
--JaJon.java
--Student.java
build.gradle
gson-2.8.8.jar

Here is my JaJson.java :

import com.google.gson.Gson; 
import com.google.gson.GsonBuilder;  
public class JaJson {

    public static void main(String args[]) {  
    System.out.println("Hello");  
    String jsonString = "{\"name\":\"Mahesh\", \"age\":21}"; 
      
    GsonBuilder builder = new GsonBuilder(); 
    builder.setPrettyPrinting(); 

    Gson gson = builder.create(); 
    Student student = gson.fromJson(jsonString, Student.class); 
    System.out.println(student);    

    jsonString = gson.toJson(student); 
    System.out.println(jsonString);  

    }  
    public JaJson(){
        System.out.println("what time is it ?");
    }

    public void getTime(){
        System.out.println("Hammer time!");
    }
}

Here is my Student.java :

public class Student { 
   private String name; 
   private int age; 
   public Student(){} 
   
   public String getName() { 
      return name; 
   }
   
   public void setName(String name) { 
      this.name = name; 
   } 
   
   public int getAge() { 
      return age; 
   }
   
   public void setAge(int age) { 
      this.age = age; 
   }
   
   public String toString() { 
      return "Student [ name: " name ", age: "  age  " ]"; 
   }  
}

Actually it works when i do a :

javac -cp gson-2.8.8.jar;*.jar;src; src/JaJson.java

then a :

java -cp gson-2.8.8.jar;*.jar;src; JaJson

it show me as expected :

Student [ name: Mahesh, age: 21 ]
{
  "name": "Mahesh",
  "age": 21
}

So here is my messy attempt to make a runnable fat jar with gradle with gson included and Student class also included :

build.gradle

apply plugin: 'java'
apply plugin: 'eclipse'
//apply plugin: 'java-library'
apply plugin: 'application'
apply plugin: 'idea'
buildscript {
    repositories {
        gradlePluginPortal()
    }
    dependencies {
        classpath 'gradle.plugin.com.github.jengelman.gradle.plugins:shadow:7.0.0'
    }
}

apply plugin: 'com.github.johnrengelman.shadow'



mainClassName = "JaJson"
// tag::repositories[]
repositories { 
    mavenCentral() 
}
// end::repositories[]

configurations {
    // configuration that holds jars to include in the jar
    extraLibs
}
sourceSets {
    single{
        java {
            srcDir 'src'
            
        }
    }
}

task compile(type: JavaCompile) {
    source = sourceSets.single.java
    sourceSets.main.java.srcDirs = ['src']
    classpath = sourceSets.main.compileClasspath
    destinationDirectory = sourceSets.main.output.classesDirs[0]

}
compileJava {
    options.release = 7
}
// tag::dependencies[]
dependencies {
    implementation 'com.google.code.gson:gson:2.8.8'
    implementation "joda-time:joda-time:2.2"
    testImplementation "junit:junit:4.12"
    shadow 'com.google.code.gson:gson:2.8.8'

}

java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(11)
    }
}

jar {
  manifest {
    attributes(
      'Class-Path': configurations.compile.collect { it.getName() }.join(' '),
      'Main-Class': 'JaJson'
    )
  }
}



task fatJar(type: Jar) {
  manifest.from jar.manifest
  classifier = 'all'
  from {
    configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
    configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
  } {
    exclude "META-INF/*.SF"
    exclude "META-INF/*.DSA"
    exclude "META-INF/*.RSA"
  }
  with jar
}

shadowJar {
   archiveBaseName.set('shadow')
   archiveClassifier.set('')
   archiveVersion.set('')
    manifest {
    inheritFrom project.tasks.fatJar.manifest
  }
}






version = '1.2.1'

Any idea on how to do a runnable fatjar with student and gson ?

regards

CodePudding user response:

With gradle 7.2, I was able to create the executable fat jar using gradle build(or ./gradlew build if you use a gradle wrapper) command just by removing one line from the build.gradle in the question. I removed 'Class-Path': configurations.compile.collect { it.getName() }.join(' '), line, from within the attributes method of jar task.

Running the generated fat jar using command java -jar build/libs/shadow.jar returns below response:

Hello
Student [ name: Mahesh, age: 21 ]
{
  "name": "Mahesh",
  "age": 21
}

CodePudding user response:

Add two dependencies

apply plugin: 'java'

repositories {
    mavenCentral()
}

dependencies {
    compile group: 'org.slf4j', name: 'slf4j-api', version: '1.7.25'
    compile group: 'org.slf4j', name: 'slf4j-simple', version: '1.7.25'
}

Using the Jar Task From the Java Plugin

We need two things to make it work:

  • a Main-Class attribute in the manifest file
  • Include dependencies jars

Let's add few modifications to the Gradle task:

jar {
    manifest {
        attributes "Main-Class": "com.baeldung.fatjar.Application"
    }

    from {
        configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
    }
}

Creating a Separate Task

If we want to leave the original jar task as it is, we can create a separate one that will do the same job.

The following code will add a new task called customFatJar:

task customFatJar(type: Jar) {
    manifest {
        attributes 'Main-Class': 'com.baeldung.fatjar.Application'
    }
    baseName = 'all-in-one-jar'
    from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
    with jar
}

Using Dedicated Plugins

We can also use existing Gradle plugins in order to build a fat jar.

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.github.jengelman.gradle.plugins:shadow:2.0.1'
    }
}

apply plugin: 'java'
apply plugin: 'com.github.johnrengelman.shadow'

Once we apply the Shadow plugin, the shadowJar task will be ready to use.

for more detail check this link

  • Related