Вы можете использовать загрузчик системных классов, чтобы найти классы в пути к загрузочному классу. Например, это
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, автор: kriegaex: вместо того, чтобы писать новый ответ на этот старый вопрос, я хочу улучшить или обновить этот очень хороший ответ, также принимая во внимание пути с пробелы и модули Java 9+.
Вот метод, возвращающий путь к файлу класса как экземпляр File
. Если файл класса является частью модуля времени выполнения JAR или Java (URL-адрес начинается с протокола jrt:
), он просто возвращает пути к JAR или файлу JMOD, что может вам не понадобиться, но это просто демонстрация того, что вы можете редактировать, сколько душе угодно. Конечно, это все еще хакерская игра, например не учитывая классы, загруженные из веб-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);
}
}
Когда я вызываю это из одного из моих проектов IntelliJ IDEA с JDK 14, установленным по пути, содержащему пробелы, и намеренно добавляю 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
person
sbridges
schedule
23.04.2011
Boot-Class-Path
, мне стало любопытно, и собранная информация помогла мне элегантно решить проблему с загрузкой агента. Я проделал последнее вручную с большим количеством шаблонного кода, теперь он просто работает до тех пор, пока пользователь не изменяет имя артефакта, прежде чем использовать его в качестве JAR агента. Так что спасибо! - person kriegaex   schedule 30.06.2020