[解決済み】Javaでクラスパスからリソースを読み込むためのURL
質問
Javaでは、同じAPIを使用しても、異なるURLプロトコルであらゆる種類のリソースを読み込むことができます。
file:///tmp.txt
http://127.0.0.1:8080/a.properties
jar:http://www.foo.com/bar/baz.jar!/COM/foo/Quux.class
これは、リソースの実際の読み込みと、リソースを必要とするアプリケーションとをうまく切り離しています。また、URLは単なる文字列なので、リソースの読み込みも非常に簡単に設定することができます。
現在のクラスローダーを使用してリソースをロードするためのプロトコルはありますか? これは、リソースがどのjarファイルまたはクラスフォルダから来るかを知る必要がないことを除けば、Jarプロトコルに似ています。
を使えばできるんです。
Class.getResourceAsStream("a.xml")
もちろん、別の API を使用する必要があり、既存のコードに変更を加える必要があります。私は、プロパティ・ファイルを更新するだけで、すでにリソースの URL を指定できるすべての場所でこれを使用できるようにしたいのです。
どのように解決するのですか?
導入と基本的な実装
まず最初に、最低でもURLStreamHandlerが必要です。 これは実際に与えられたURLへの接続を開くものです。 これは単に
Handler
を指定することができます。
java -Djava.protocol.handler.pkgs=org.my.protocols
と入力すると、サポートされているプロトコル(この場合は "classpath")として "simple"パッケージ名を使用して、自動的にピックアップされるようになっています。
使用方法
new URL("classpath:org/my/package/resource.extension").openConnection();
コード
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();
}
}
起動時の問題
私のような人は、起動時に設定されるプロパティに頼ってどこかに行くのは嫌でしょう(私の場合、Java WebStart のように選択肢を広げておきたいのです - だからこそ I がすべて必要です)。
回避策/強化策
マニュアルコード ハンドラ仕様
コードを制御する場合、以下のようなことが可能です。
new URL(null, "classpath:some/package/resource.extension", new org.my.protocols.classpath.Handler(ClassLoader.getSystemClassLoader()))
で、これは接続を開くためにあなたのハンドラを使用します。
しかし、これもまた満足のいくものではありません。なぜなら、これをするためにURLは必要ないからです。あなたがコントロールできない(あるいはしたくない)あるライブラリはURLを欲しているので、これをしたいのです...。
JVMハンドラの登録
究極のオプションは
URLStreamHandlerFactory
は、jvm 全体ですべての URL を処理します。
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);
}
}
ハンドラを登録するには
URL.setURLStreamHandlerFactory()
を設定したファクトリーで実行します。 そして
new URL("classpath:org/my/package/resource.extension")
最初の例と同じように、これで完了です。
JVMハンドラ登録の問題
このメソッドは、JVMごとに一度だけ呼び出すことができることに注意してください。また、TomcatはJNDIハンドラを登録するためにこのメソッドを使用することに注意してください(AFAIK)。 Jettyを試してみてください(私はそうします); 最悪の場合、最初にこのメソッドを使用することができ、その後、あなたの周りで動作する必要があります!
ライセンス
これをパブリックドメインとして公開しますが、改変する場合は、どこかでOSSプロジェクトを立ち上げ、その詳細をここにコメントしていただくようお願いします。 より良い実装としては
URLStreamHandlerFactory
を使用することで
ThreadLocal
を格納するために
URLStreamHandler
は、各
Thread.currentThread().getContextClassLoader()
. 私の修正とテストクラスもあげます。
関連
-
[解決済み] ブラウザによって異なるURLの最大長とは?
-
[解決済み] リモート Git リポジトリの URI (URL) を変更するには?
-
[解決済み] URI、URL、URNの違いは何ですか?
-
[解決済み] JavaにおけるHashMapとHashtableの違いは何ですか?
-
[解決済み] Javaにおけるpublic、protected、package-private、privateの違いは何ですか?
-
[解決済み] JavaScriptで現在のURLを取得する?
-
[解決済み] ページを再読み込みせずにURLを変更するにはどうすればよいですか?
-
[解決済み] Java で、あるコンストラクタを別のコンストラクタから呼び出すにはどうすればよいですか?
-
[解決済み] Javaで文字列値からenum値を取得する方法
-
[解決済み】「GET」パラメータから値を取得する(JavaScript)【重複】。
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] maven. -source 1.5ではラムダ式がサポートされていません。
-
[解決済み] Application startメソッドで例外が発生する。JavaFx 11
-
[解決済み] パラメータ[変数]の不正な修飾子;finalのみが許可される[closed]。
-
[解決済み] なぜJPAには@Transientアノテーションがあるのですか?
-
[解決済み] java.lang.ClassCastException: java.util.Arrays$ArrayList は java.util.ArrayList にキャストできません。
-
[解決済み] 一部の入力ファイルが非推奨のAPIを使用またはオーバーライドしている
-
[解決済み] 午前0時からの時間を秒単位で取得する方法
-
[解決済み] Mavenです。JARは空になります - 含有するためにマークされたコンテンツがありません
-
[解決済み] アニメーションGIFの表示
-
[解決済み] 文字列の巻き方