3

を使用してbootclasspathに配置したjavaagentjarがあります

Boot-Class-Path: myagent.jar

MANIFEST.MFファイル内。

jarが配置されているファイルシステム上のディレクトリを見つける必要があります。

ただし、ここで説明する方法は、私にはうまくいかないようです。

 new File(MyClass.class.getProtectionDomain().getCodeSource().getLocation().toURI().g­etPath());

この場合、ProtectionDomain.getCodeSource()はnullを返します。jarがブートクラスパスに配置されているため、これが発生していると思います。このため、リソースの場所を取得するためにMyClass.getClassLoader()を実行することもできません。

私はJava6を使用しています。

誰かが瓶の場所を取得する方法を教えてもらえますか?

4

2 に答える 2

9

システム クラス ローダーを使用して、ブート クラス パス上のクラスを検索できます。たとえば、これ

System.out.println(
  ClassLoader.getSystemClassLoader().getResource("java/lang/String.class")
);

次のようなものを出力します。

jar:file:/C:/Program%20Files/Java/jdk1.6.0_22/jre/lib/rt.jar!/java/lang/String.class

MyClass.classディスク上の の場所を見つけるには、次のようにします。

String urlString = ClassLoader
 .getSystemClassLoader()
 .getResource("com/my/package/MyClass.class")
 .toString();

urlString = urlString.substring(urlString.indexOf("file:"), urlString.indexOf('!'));
URL url = new URL(urlString);
File file = new File(url.toURI());
System.out.println(file);
System.out.println(file.exists());

更新 2020-06-29 by kriegaex : この古い質問に対する新しい回答を書くのではなく、この非常に優れた回答を強化または更新し、スペースと Java 9+ モジュールを含むパスも考慮したいと考えています。

Fileクラス ファイル パスをインスタンスとして返すメソッドを次に示します。クラス ファイルが JAR または Java ランタイム モジュール (URL は protocol で始まるjrt:) の一部である場合、JAR または JMOD ファイルへのパスが返されるだけです。心ゆくまで編集してください。もちろん、これはまだハックです。たとえば、ファイルからではなく Web URL からロードされたクラスを考慮していませんが、アイデアはわかります。

public static File getFileForClass(String className) {
  className = className.replace('.', '/') + ".class";
  URL classURL = ClassLoader.getSystemClassLoader().getResource(className);
  if (classURL == null)
    return null;
  System.out.println("Class file URL: " + classURL);

  // Adapt this if you also have '.war' or other archive types
  if (classURL.toString().contains(".jar!")) {
    String jarFileName = classURL.getPath().replaceFirst("!.*", "");
    System.out.println("Containing JAR file: " + jarFileName);
    try {
      return new File(new URL(jarFileName).toURI());
    }
    catch (URISyntaxException | MalformedURLException e) {
      throw new RuntimeException(e);
    }
  }

  if (classURL.getProtocol().equals("jrt")) {
    String jrtModule = classURL.getFile().replaceFirst("/([^/]+).*", "$1");
    System.out.println("Target class is part of Java runtime module " + jrtModule);
    String jmodName = System.getProperty("java.home") + "/jmods/" + jrtModule + ".jmod";
    System.out.println("Containing Java module file: " + jmodName);
    return new File(jmodName);
  }
  try {
    return new File(classURL.toURI());
  }
  catch (URISyntaxException e) {
    throw new RuntimeException(e);
  }
}

スペースを含むパスの下にJDK 14がインストールされたIntelliJ IDEAプロジェクトの1つからこれを呼び出し、テスト用のスペースを含むパスも含むJARを意図的に追加すると、このコード...

public static void main(String[] args) throws IOException {
  Instrumentation instrumentation = ByteBuddyAgent.install();
  instrumentation.appendToSystemClassLoaderSearch(
    new JarFile("C:/Program Files/JetBrains/IntelliJ IDEA 2018.3/lib/idea_rt.jar")
  );
  Stream
    .of(
      Weaver.class.getName(),
      String.class.getName(),
      ByteBuddy.class.getName(),
      "com.intellij.execution.TestDiscoveryListener"
    )
    .forEach(className -> System.out.printf("Found file: %s%n%n", getFileForClass(className)));
}

... このコンソール出力が生成されます。

Class file URL: file:/C:/Users/alexa/Documents/java-src/Sarek/sarek-aspect/target/classes/dev/sarek/agent/aspect/Weaver.class
Found file: C:\Users\alexa\Documents\java-src\Sarek\sarek-aspect\target\classes\dev\sarek\agent\aspect\Weaver.class

Class file URL: jrt:/java.base/java/lang/String.class
Target class is part of Java runtime module java.base
Containing Java module file: C:\Program Files\Java\jdk-14.0.1/jmods/java.base.jmod
Found file: C:\Program Files\Java\jdk-14.0.1\jmods\java.base.jmod

Class file URL: jar:file:/C:/Users/alexa/.m2/repository/net/bytebuddy/byte-buddy/1.10.13/byte-buddy-1.10.13.jar!/net/bytebuddy/ByteBuddy.class
Containing JAR file: file:/C:/Users/alexa/.m2/repository/net/bytebuddy/byte-buddy/1.10.13/byte-buddy-1.10.13.jar
Found file: C:\Users\alexa\.m2\repository\net\bytebuddy\byte-buddy\1.10.13\byte-buddy-1.10.13.jar

Class file URL: jar:file:/C:/Program%20Files/JetBrains/IntelliJ%20IDEA%202018.3/lib/idea_rt.jar!/com/intellij/execution/TestDiscoveryListener.class
Containing JAR file: file:/C:/Program%20Files/JetBrains/IntelliJ%20IDEA%202018.3/lib/idea_rt.jar
Found file: C:\Program Files\JetBrains\IntelliJ IDEA 2018.3\lib\idea_rt.jar
于 2011-04-23T06:14:26.177 に答える
0

次のようなことができます。

final String   bootClassPath;
final String[] entries;

// different VM may use a different string here...
bootClassPath = System.getProperty("sun.boot.class.path");
entries       = bootClassPath.split(File.pathSeparator);

for(final String entry : entries)
{
    System.out.println(entry);
}

これは、ブート クラスパスの各エントリを通過します。エントリごとに JAR ファイルを取得し、マニフェスト ファイルを見て、それが自分のものかどうかを確認できます。見つける固有のものがまだない場合は、マニフェストに別のエントリを追加して探すことができます。

于 2011-04-23T04:34:45.283 に答える