返回文章列表文章索引阅读全文
STARBLOG / 阅读手记
Java

Deep Dive into JAR Packages: Building Executable JARs with Gradle and Accessing Folders and Files Inside JARs

Preface Java's cross-platform capability sounds tempting and delicious, billed as “Write Once, Run Everywhere,” but in reality it's “Run Once, Debug Everywhere”... In actual development you still run into all kinds of pitfalls. Having just solved a series of issues, I specifically wrote this article to summarize them. Building JAR Packages with Gradle Thanks to the almighty Gradle, which greatly improves Java development productivity~ In Gradle you can generate a JAR using the official plugin: a

曦远 (DealiAxy)约 14 分钟
目录6 个章节

Preface

Java's cross-platform capability sounds tempting and delicious, billed as “Write Once, Run Everywhere,” but in reality it's “Run Once, Debug Everywhere”... In actual development you still run into all kinds of pitfalls. Having just solved a series of issues, I specifically wrote this article to summarize them.

Building JAR Packages with Gradle

Thanks to the almighty Gradle, which greatly improves Java development productivity~ In Gradle you can generate a JAR using the official plugin: application to simply generate a JAR, and there are also many different configurations you can customize. For details, please refer to the official Gradle documentation.

Here I'm using a Gradle plugin called shadow, which has the JAR-building configuration all laid out clearly—very convenient! Official docs: https://imperceptiblethoughts.com/shadow/configuration/#configuring-output-name

Below is a build.gradle configuration reference:

plugins {
    id 'com.github.johnrengelman.shadow' version '4.0.3'

    // Apply the java plugin to add support for Java
    id 'java'

    // Apply the application plugin to add support for building an application
    id 'application'
}

dependencies {
    implementation 'com.github.jengelman.gradle.plugins:shadow:4.0.3'
}

// Output to build/libs/name.jar
shadowJar {
    baseName = 'name'
    classifier = null
    version = null
}

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

The specific configuration should be set according to the project's actual needs~ After setting up the shadow plugin, run gradle build and you can generate your executable JAR under the build/libs/ folder—super convenient. For more features you can check the shadow official documentation; it's written very clearly.

Accessing Resources Inside a JAR

Although a JAR has various directory structures, a JAR is still essentially a file, so you cannot access it with traditional methods. Things like the File class and the Class object's getResouce method won't work. You should use the ClassLoader's getResourceStream method to directly obtain the input stream of the resource file. For example:

InputStream is=this.getClass().getResourceAsStream("/resource/res.txt");
InputStream is=this.getClass().getClassLoader().getResourceStream("/resource/res.txt");

Note: The getResourceStream methods of the Class object and the ClassLoader object are also different. For the specific differences, you can check this note: Correctly Obtaining Java Project Resources

Accessing Folders Inside a JAR

When there are many resource files in a JAR, you can't possibly enter names one by one to fetch them—that's way too hacky. You definitely want an automated approach to improve productivity. In fact, accessing folders inside a JAR is quite troublesome, but I still found a clever workaround, and after trying it, it works pretty well. (Though it's best to add some caching)

The code is as follows:

String path = getClass().getProtectionDomain().getCodeSource().getLocation().getPath();
JarFile localJarFile = new JarFile(new File(path));

Enumeration<JarEntry> entries = localJarFile.entries();
while (entries.hasMoreElements()) {
      JarEntry jarEntry = entries.nextElement();
      String innerPath = jarEntry.getName();
      System.out.println(innerPath);
}

Use getClass().getProtectionDomain().getCodeSource().getLocation().getPath(); to get the path of the current JAR. If the code is not running inside a JAR, what you get is the path of the current class file. So before using it, it's best to add a check to see whether the program is running inside a JAR.

About JavaFX Media Resource Issues

JavaFX can play music, but unlike other Image and Font resources, the Media object's constructor can only accept a String parameter (i.e., a file URL), so there's no way to use the getResourceStream method to pass the file input stream into the object.

I looked it up on the official site and found a solution: just change the file URL to a JarURL. Docs: https://docs.oracle.com/javase/6/docs/api/java/net/JarURLConnection.html.

Simple example:

String path = String.format("jar:file:%s!/%s", jarPath, relativePath);
Media media = new Media(path);

Note: The form of relativePath is like media/hello.wav.

Welcome to Discuss

Programming Lab focuses on exploring popular new internet technologies and practicing team agile development. Reply with linux, flutter, c#, netcore, android, kotlin, java, python, etc. in the backend of the WeChat official account “Programming Lab” to get related technical articles and materials, and if you have any questions you can also leave a message in the official account backend~

_EOF_

Deep Dive into JAR Packages: Building Executable JARs with Gradle and Accessing Folders and Files Inside JARs

本文作者:
程序设计实验室
版权声明:
本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

相关文章

Java开发:JDK安装和环境配置

前言 环境配置是开发中最基础的部分,不过最近有很多新入坑的同学,都在问怎么安装JDK和配置环境,索性写一篇。 这里要注意一下,在Windows平台和Linux平台下做开发是不同的,Windows平台开发Java需要自己手动配置JDK的环境变量,而大多数Linux都是不需要的,安装了OpenJDK就可以了(可能很多发行版都自带了OpenJDK),这点是比较方便的。 下载Java JDK Window

2023-02-08 · Java · 约 1 分钟

Spring-Boot:创建第一个应用

简介 Spring Boot 是一个轻量级框架,可以完成基于 Spring 的应用程序的大部分配置工作。在本教程中,将学习如何使用 Spring Boot 的 starter、特性和可执行 JAR 文件结构,快速创建能直接运行的基于 Spring 的应用程序。 本文使用IDEA作为开发工具,Gradle作为构建工具,创建一个简单的SpringBoot应用,暂时不涉及数据库的配置。 使用IDEA创建

2022-05-27 · Java · 约 1 分钟

讨论

共 0 条

良言一句三冬暖,恶语伤人六月寒。

加载评论中…