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
目录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~
- Blog Garden: https://www.cnblogs.com/deali/
- Coding livestream: https://live.bilibili.com/11883038
- Zhihu: https://www.zhihu.com/people/dealiaxy
_EOF_
Deep Dive into JAR Packages: Building Executable JARs with Gradle and Accessing Folders and Files Inside JARs
- 本文作者:
- 程序设计实验室
- 版权声明:
- 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
相关文章
Java使用JDBC操作SQLite
SQLite介紹 SQLite是一個輕量級的資料庫系統,不需要安裝就可以使用,也可以十分容易的就內嵌於系統內,FireFox就內嵌SQLite,可以在FireFox上直接使用JavaScript來呼叫操作資料庫。 SQLite是由C語言撰寫而已,可以跨Linux及Windows等平台,在Java存取及操作上則可使用JDBC來連線SQLite。 在JDBC連線SQLite上,大概分成二種方式,一種是
2021-12-18 · Java · 约 1 分钟
Apache-Commons-IO-最佳实践
本文列举了Java输入输出部分(IO area)的大量“最佳实践”(best practices)。 java.io.File 通常你需要去处理文件或文件名时,有许多会出错的情况: 一个类可在Unix运行但不能在Windows运行,反之亦然。 由于双路径分隔符(path separator)或缺失路径分隔符(path separator)导致文件名无效。 (在Windows上的)符合通用命名标准(
2022-05-27 · Java · 约 1 分钟
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 条加载评论中…