DEV Community

Cover image for JeKa: The Simplest Way to Create Uber and Shade Jars
Jerome Angibaud
Jerome Angibaud

Posted on

JeKa: The Simplest Way to Create Uber and Shade Jars

JeKa is a modern Java build tool focused on simplicity.

This post is part of the "Jeka: the simplest way to..." series and shows how to create a fat jar (shaded or not) effortlessly.

For Applications : Simple Fat Jar

A common way to package Java applications is by creating FAT jars. A fat jar bundles all classes from the dependencies, so you only need the jar (along with the Java Runtime) to run the application.

Your application may need dependencies, which you can list in the dependencies.txt file as shown in the example below:

== COMPILE ==
com.github.lalyos:jfiglet:0.0.9
com.google.guava:guava:33.4.0-jre
com.fasterxml.jackson.core:jackson-core:2.18.2


== TEST ==
org.junit.jupiter:junit-jupiter:5.8.1
Enter fullscreen mode Exit fullscreen mode

To configure the fat jar generation, edit the jeka.properties file:

jeka.version=0.11.11
jeka.java.version=17

@project.pack.detectMainClass=true
@project.pack.jarType=FAT
Enter fullscreen mode Exit fullscreen mode

The @project.pack.jarType property specifies the type of JAR to generate. It can be REGULAR, FAT, or SHADE.

The @project.pack.detectMainClass=true setting instructs Jeka to detect the main class to include in the manifest file.

To generate the jar, run the following command:

jeka project: pack
Enter fullscreen mode Exit fullscreen mode

The FAT jar will be created in the jeka-output directory. To run it, just execute: java -jar [jar-name].jar.

For Libraries : Shade Fat jar

For libraries, a good practice consists in keeping a regular Jar and providing a Fat Jar as an additional option.

Ideally, dependency classes should also be relocated to a specific package to avoid classpath conflicts for the consumers. We call a shade jar, a fat jar where the dependencies classes have been re-located in a specific package.

To create such a jar, configure JeKa as follows:

jeka.version=0.11.11
jeka.java.version=17

@project.moduleId=org.examples:my-lib
@project.version=1.0.0-SNAPSHOT
@project.pack.shadeJarClassifier=all

@maven.publication.extraArtifacts=all
Enter fullscreen mode Exit fullscreen mode

Now, invoking jeka prpject: pack will also create a*org.examples.my-lib-all.jar* file.
By opening the jat file, we can see that all dependency classes has been automatically re-located.

.
├── org                  
│   └── example             
│       └── mylib           <- Base package for my-lib classes
│           ├── MyLyb.class   
│           └── _shaded     <- Base package for dependency classes
│               ├── com.google...
│               ├── com.fasterxml.jackson...
│               └── com.github.lalyos.jfiglat...
└── META-INF             
    └── MANIFEST.MF      

Enter fullscreen mode Exit fullscreen mode

Additionally, @maven.publication.extraArtifacts=all includes the shade jar in the maven publication generated by jeka maven: publish command.

Maven Comparison

As shown below, Maven requires significantly more typing to achieve a similar goal.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>


    <groupId>org.examples</groupId>
    <artifactId>my-lib</artifactId>
    <version>0.1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>com.github.lalyos</groupId>
            <artifactId>jfiglet</artifactId>
            <version>0.0.9</version>
        </dependency>
        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>33.2.1-jre</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.17.2</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
                <version>2.3</version>
                <executions>
                    <!-- Run shade goal on package phase -->
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-shade-plugin</artifactId>
                    <version>2.1</version>
                    <executions>
                        <execution>
                            <phase>package</phase>
                            <goals>
                                <goal>shade</goal>
                            </goals>
                        </execution>
                    </executions>
                    <configuration>
                        <minimizeJar>true</minimizeJar>
                        <artifactSet>
                            <includes>
                                <include>com.google.guava:guava</include>
                                <include>com.github.lalyos:jfiglet</include>
                                <include>com.fasterxml.jackson.core:jackson-core</include>
                            </includes>
                        </artifactSet>
                        <relocations>
                            <relocation>
                                <pattern>com.google.common</pattern>
                                <shadedPattern>org.elasticsearch.common</shadedPattern>
                            </relocation>
                            <relocation>
                                <pattern>com.fasterxml.jackson</pattern>
                                <shadedPattern>org.elasticsearch.common.jackson</shadedPattern>
                            </relocation>
                        </relocations>
                        <filters>
                            <filter>
                                <artifact>*:*</artifact>
                                <excludes>
                                    <exclude>META-INF/license/**</exclude>
                                    <exclude>META-INF/*</exclude>
                                    <exclude>META-INF/maven/**</exclude>
                                    <exclude>LICENSE</exclude>
                                    <exclude>NOTICE</exclude>
                                    <exclude>/*.txt</exclude>
                                    <exclude>build.properties</exclude>
                                </excludes>
                            </filter>
                        </filters>
                    </configuration>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>

</project>
Enter fullscreen mode Exit fullscreen mode

Conclusion

Jeka makes building Java projects significantly easier, with minimal configuration compared to Maven or Gradle.

Explore more examples to discover how Jeka can adapt to your project’s needs!

Top comments (0)