実行中クラスのクラスパスもしくはjarファイルの取得
Javaのプログラム実行時に、以下を検出したい場合がある。
- Eclipse等の開発環境で動作しているのか、つまり一時的にコンパイル出力された.classの集合の上で動作しているのか、あるいは製品としてjarにまとめられた状態で動作しているのか。
- 開発環境であれば、そのクラスパスは何か。
- 製品jarであれば、そのjarファイルは何か。
これを検出する。
package sample;
import java.io.*;
import java.net.*;
/**
* 実行中のクラスのクラスパスを取得する。
* 開発環境の場合は、そのクラスパス(フォルダ)、jarでの実行の場合はjarファイルを返す。
* @author ysugimura
*/
public class ClassPathLocator {
/**
* 実行中のjarファイルを返す。jarでない場合(開発環境の場合)はクラスパスを返す。
* @return jarファイル、あるいはクラスパス
*/
public static File getLocation() {
// このクラスのリソースURLを求める
URL classUrl = ClassPathLocator.class.getResource(ClassPathLocator.class.getSimpleName() + ".class");
// ドットの数を数えて、このクラスのパッケージ階層数を取得する。
int pkgHier = (int)ClassPathLocator.class.getName().chars().filter(c->c == '.').count();
// このクラスの格納されているjarファイルを取得する。jarでない場合(開発環境の場合)はフォルダを返す。
return getLocationFromClassUrl(classUrl, pkgHier);
}
/**
* .classのリソースURLからjarファイルを取得する。
* jarでの実行でない場合(開発環境の場合)はクラスパスを返す。
* @param url .classのリソースURL
* @param pkgHier このクラスのパッケージ階層数
* @return .classがjar内にある場合、そのjarファイル。jarではない場合はそのクラスパス
*/
static File getLocationFromClassUrl(URL url, int pkgHier) {
// jar:の場合
if (url.getProtocol().equals("jar")) {
try {
JarURLConnection conn = (JarURLConnection)url.openConnection();
//修正した return new File(conn.getJarFileURL().getFile());
return URLUtil.getFile(conn.getJarFileURL());
} catch (Exception ex) {
return null;
}
}
// file:の場合
if (url.getProtocol().equals("file")) {
File file = new File(url.getFile()).getParentFile();
for (int i = 0; i < pkgHier; i++) file = file.getParentFile();
return file;
}
// ありえない
throw new RuntimeException("Could not determine jar or file");
}
}
URLUtil
/**
* {@link URL#getFile()}は使用できない。
* URLでは漢字等がエンコーディングされているが、getFile()はエンコーディング状態のまま取得してしまう。
* @author ysugimura
*/
public class URLUtil {
/** fileの{@link URL}から{@link Path}を取得する */
public static Path getPath(URL url) {
try {
return Paths.get(url.toURI());
} catch (URISyntaxException ex) {
throw new RuntimeException(ex);
}
}
/** fileの{@link URL}から{@link File}を取得する */
public static File getFile(URL url) {
return getPath(url).toFile();
}
}
ClassPathLocator.getLocation()で返されるFileは、
- 開発環境であれば、そのクラスパスであるフォルダ
- 製品jarであれば、そのjarファイル
になる。File#isDirectory()を使って両者を区別する。