URL to load resources from the classpath in Java
In Java, you can load all kinds of resources using the same API but with different URL protocols:
file:///tmp.txt
http://127.0.0.1:8080/a.properties
jar:http://www.foo.com/bar/baz.jar!/COM/foo/Quux.class
This nicely decouples the actual loading of the resource from the application that needs the resource, and since a URL is just a String, resource loading is also very easily configurable.
Is there a protocol to load resources using the current classloader? This is similar to the Jar protocol, except that I do not need to know which jar file or class folder the resource is coming from.
I can do that using Class.getResourceAsStream("a.xml"), of course, but that would require me to use a different API, and hence changes to existing code. I want to be able to use this in all places where I can specify a URL for the resource already, by just updating a property file.
Intro and basic Implementation
First up, you're going to need at least a URLStreamHandler. This will actually open the connection to a given URL. Notice that this is simply called Handler; this allows you to specify java -Djava.protocol.handler.pkgs=org.my.protocols and it will automatically be picked up, using the "simple" package name as the supported protocol (in this case "classpath").
Usage
new URL("classpath:org/my/package/resource.extension").openConnection();
Code
package org.my.protocols.classpath;
import java.io.IOException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;
/** A {@link URLStreamHandler} that handles resources on the classpath. */
public class Handler extends URLStreamHandler {
/** The classloader to find resources from. */
private final ClassLoader classLoader;
public Handler() {
this.classLoader = getClass().getClassLoader();
}
public Handler(ClassLoader classLoader) {
this.classLoader = classLoader;
}
@Override
protected URLConnection openConnection(URL u) throws IOException {
final URL resourceUrl = classLoader.getResource(u.getPath());
return resourceUrl.openConnection();
}
}
Launch issues
If you're anything like me, you don't want to rely on a property being set in the launch to get you somewhere (in my case, I like to keep my options open like Java WebStart - which is why I need all this).
Workarounds/Enhancements
Manual code Handler specification
If you control the code, you can do
new URL(null, "classpath:some/package/resource.extension", new org.my.protocols.classpath.Handler(ClassLoader.getSystemClassLoader()))
and this will use your handler to open the connection.
But again, this is less than satisfactory, as you don't need a URL to do this - you want to do this because some lib you can't (or don't want to) control wants urls...
JVM Handler registration
The ultimate option is to register a URLStreamHandlerFactory that will handle all urls across the jvm:
package my.org.url;
import java.net.URLStreamHandler;
import java.net.URLStreamHandlerFactory;
import java.util.HashMap;
import java.util.Map;
class ConfigurableStreamHandlerFactory implements URLStreamHandlerFactory {
private final Map<String, URLStreamHandler> protocolHandlers;
public ConfigurableStreamHandlerFactory(String protocol, URLStreamHandler urlHandler) {
protocolHandlers = new HashMap<String, URLStreamHandler>();
addHandler(protocol, urlHandler);
}
public void addHandler(String protocol, URLStreamHandler urlHandler) {
protocolHandlers.put(protocol, urlHandler);
}
public URLStreamHandler createURLStreamHandler(String protocol) {
return protocolHandlers.get(protocol);
}
}
To register the handler, call URL.setURLStreamHandlerFactory() with your configured factory. Then do new URL("classpath:org/my/package/resource.extension") like the first example and away you go.
JVM Handler Registration Issue
Note that this method may only be called once per JVM, and note well that Tomcat will use this method to register a JNDI handler (AFAIK). Try Jetty (I will be); at worst, you can use the method first and then it has to work around you!
License
I release this to the public domain, and ask that if you wish to modify that you start a OSS project somewhere and comment here with the details. A better implementation would be to have a URLStreamHandlerFactory that uses ThreadLocals to store URLStreamHandlers for each Thread.currentThread().getContextClassLoader(). I'll even give you my modifications and test classes.
URL to load resources from the classpath in Java的更多相关文章
- Load resources from classpath in Java--reference
In general classpath is the path where JVM can find .class files and resources of your application a ...
- The SSL certificate used to load resources from xxx will be distrusted in M70.
今天在浏览网站的时候遇到如下报警信息: The SSL certificate used to load resources from https://xxx.com will be distrust ...
- Java 实例 - 如何执行指定class文件目录(classpath) Java 实例 J
Java 实例 - 如何执行指定class文件目录(classpath) Java 实例 如果我们 Java 编译后的class文件不在当前目录,我们可以使用 -classpath 来指定class ...
- 环境变量/path/classpath/JAVA_HOME/JAVA环境变量配置
环境变量 环境变量是在操作系统中一个具有特定名字的对象,它包含了一个或者多个应用程序所将使用到的信息.例如Windows和DOS操作系统中的path环境变量,当要求系统运行一个程序而没有告诉它程序所在 ...
- path 与classpath针对JAVA来说
Path 路径,是java编译时需要调用的程序(如java,javac等)所在的地方CLASSPATH 类的路径,在编译运行java程序时,如果有调用到其他类的时候,在classpath中寻找需要的类 ...
- 使用任意的输入流(InputStream)实例,包括字符串形式的文件路径或者 file:// 的 URL 形式的文件路径来配置
mybatis – MyBatis 3 | 入门 http://www.mybatis.org/mybatis-3/zh/getting-started.html 从 XML 中构建 SqlSessi ...
- How to load a local .CSS file & JavaScript resources using iPhone UIWebView Class
This post will cover the basic setup and creation of an application with web content for iPhone that ...
- springboot-项目获取resources下文件碰到的问题(classPath下找不到文件和文件名乱码)
项目是spring-boot + spring-cloud 并使用maven 管理依赖.在springboot+maven项目下怎么读取resources下的文件实现文件下载? 怎么获取resourc ...
- 一个编译可执行jar包 jar包中不包含resources下config.properties且可以读到config.properties文件且classpath中有当前路径的pom
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/20 ...
随机推荐
- Java Object类及其equals方法
基本概念: Object类位于java.lang包中,java.lang包包含着Java最基础和核心的类,在编译时会自动导入: Object类是所有Java类的祖先.每个类都使用 Object 作为超 ...
- modal结合art-template
内容div <div id="modal-cont"></div> 模板tpl <script id="modal-tpl" ty ...
- 学习笔记36—坚果云 | Papership或Zotero使用webDAV验证服务器不成功怎么办?
很多人都喜欢用坚果云作为Zotero的第三方云盘,从而无限扩展Zotero的存储空间.可是大家在Papership或zotero客户端中验证坚果云webDAV服务器时,会出现验证不成功的问题,相信这个 ...
- ubuntu 18.04编译opencv3.4.3 with python3.6 cuda9.2 gdal
惭愧,之前一直没在linux下编译过opencv,也没用过纯命令行版的cmake,现在咬牙编译一次.其实感觉还凑合. opencv官网文档还是那么烂:https://docs.opencv.org/m ...
- DataGrid的列上添加日期控件
今天的使用EasyUI datagrid的时候,遇到了如下问题,如下图:
- 手机网页唤醒app,
1.在系统系统自带的浏览器中 首先做成HTML的页面,页面内容格式如下: <a href="[scheme]://[host]/[path]?[query]">启动应用 ...
- windows/browser ----> cmd命令/powershell命令/chrome插件vimuim命令
windows 7 cmd常用命令: 1.进入某盘,比如d盘:d:(有一个冒号) 2.显示d盘的文件夹和文件:dir 3.进入d盘某个文件夹:cd filename 4.清除屏幕:cls 5.查看ip ...
- English Voice of <<City of stars>>
City of stars 星光之城啊 Are you shining just for me? 你是否只愿为我闪耀 City of stars 星光之城啊 There's so much that ...
- English Voice of <<All Of Me>>
"All Of Me"我的一切 [Verse 1:]What would I do without your smart mouth没有你的蜜语甜言,我该怎办Drawing me ...
- 使用VisualStudio进行脚本|样式文件压缩
在vs的Optimization中有个Bundle是专门用来压缩样式和脚本文件 .他有两个继承:StyleBundle.ScriptBundle,从名字上就可看出,StyleBundle专门压缩样式文 ...