曦远 (DealiAxy)一份私人的文字刊物

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 许可协议。转载请注明出处!

相关文章

JavaWeb开发---Servlet的生命周期实验

前言 Servlet是运行在服务器端的程序,它的运行状态由Servlet容器(简称容器)来维护。 通常,在容器收到客户对Servlet的请求时,容器会判断这个Servlet是否为第一次被访问,如果是第一次被访问,则会创建一个Servlet实例同时调用该实例的init()方法,进行初始化。 每个Servlet只会被创建一个实例,同时也只会被初始化一次。然后将这个实例一直保存在内存中,对所有的请求进行

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

JavaWeb开发---使用IDEA创建Servlet程序

前言 最近做项目需要,从之前熟悉的PHP和Python转到了JavaWeb,所以就有了这个笔记。资源图片都是来自网上的资源,根据自己的实际操作应用,做了总结归纳。 所需工具 JDK Tomcat IDEA 创建工程 设置工程名字: 创建完成后工程结构如下: 上面的图片是在网络上复制的,好像我用的IDEA 2017.3.2没有这个Create web.xml的选项,我也不知道为啥,难道是IDEA越更

2021-12-18 · Java · 约 1 分钟

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

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

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

讨论

共 0 条

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

加载评论中…