getProtectionDomain Подход выдает базовое местоположение класса (например, содержащий JAR-файл). Однако возможно, что политика безопасности среды выполнения Java выдаст ошибку SecurityException при вызове getProtectionDomain(), поэтому, если вашему приложению необходимо работать в различных средах, лучше всего протестировать во всех из них.
getResource Подход выдает полный путь к ресурсу URL класса, с помощью которого вам нужно будет выполнить дополнительные манипуляции со строками. Это может быть file: путь, но это также может быть jar:file: или даже что-то более неприятное, как bundleresource://346.fwk2106232034:4/foo/Bar.class при выполнении в рамках OSGi. И наоборот, getProtectionDomain подход корректно выдает file: URL-адрес даже из OSGi.
Обратите внимание, что оба getResource("") и getResource(".") завершились ошибкой в моих тестах, когда класс находился внутри JAR-файла; оба вызова вернули null. Поэтому я рекомендую вместо этого вызов # 2, показанный выше, поскольку он кажется более безопасным.
Шаг 2: URL чтобы File
В любом случае, как только у вас будет URL, следующим шагом будет преобразование в File. Это отдельная проблема; смотрите Сообщение в блоге Кохсуке Кавагучи об этом для получения полной информации, но, вкратце, вы можете использовать new File(url.toURI()) при условии, что URL полностью правильно сформирован.
Наконец, я бы настоятельно не рекомендовал использовать URLDecoder. Некоторые символы URL, : и / в частности, недопустимые символы в кодировке URL. Из URLDecoder Javadoc:
Предполагается, что все символы в закодированной строке являются одним из следующих: от "a" до "z", от "A" до "Z", от "0" до "9", и "-", "_", ".", и "*". Символ "%" разрешен, но интерпретируется как начало специальной экранируемой последовательности.
...
Есть два возможных способа, которыми этот декодер мог бы обрабатывать недопустимые строки. Он мог бы либо оставить недопустимые символы в покое, либо выдать исключение IllegalArgumentException . Какой подход использует декодер, зависит от реализации.
На практике, URLDecoder как правило, не выдает ошибкуIllegalArgumentException, как угрожалось выше. И если ваш путь к файлу содержит пробелы, закодированные как %20, этот подход может показаться работающим. Однако, если ваш путь к файлу содержит другие не буквенные символы, такие как + у вас возникнут проблемы с URLDecoder искажением пути к файлу.
Рабочий код
Для выполнения этих шагов у вас могут быть методы, подобные следующим:
/** * Gets the base location of the given class. * <p> * If the class is directly on the file system (e.g., * "/path/to/my/package/MyClass.class") then it will return the base directory * (e.g., "file:/path/to"). * </p> * <p> * If the class is within a JAR file (e.g., * "/path/to/my-jar.jar!/my/package/MyClass.class") then it will return the * path to the JAR (e.g., "file:/path/to/my-jar.jar"). * </p> * * @param c The class whose location is desired. * @see FileUtils#urlToFile(URL) to convert the result to a {@link File}. */ publicstatic URL getLocation(final Class<?> c) { if (c == null) returnnull; // could not load the class
// try the easy way first try { finalURLcodeSourceLocation= c.getProtectionDomain().getCodeSource().getLocation(); if (codeSourceLocation != null) return codeSourceLocation; } catch (final SecurityException e) { // NB: Cannot access protection domain. } catch (final NullPointerException e) { // NB: Protection domain or code source is null. }
// NB: The easy way failed, so we try the hard way. We ask for the class // itself as a resource, then strip the class's path from the URL string, // leaving the base path.
// get the class's raw resource path finalURLclassResource= c.getResource(c.getSimpleName() + ".class"); if (classResource == null) returnnull; // cannot find class resource
/** * Converts the given {@link URL} to its corresponding {@link File}. * <p> * This method is similar to calling {@code new File(url.toURI())} except that * it also handles "jar:file:" URLs, returning the path to the JAR file. * </p> * * @param url The URL to convert. * @return A file path suitable for use with e.g. {@link FileInputStream} * @throws IllegalArgumentException if the URL does not correspond to a file. */ publicstatic File urlToFile(final URL url) { returnurl== null ? null : urlToFile(url.toString()); }
/** * Converts the given URL string to its corresponding {@link File}. * * @param url The URL to convert. * @return A file path suitable for use with e.g. {@link FileInputStream} * @throws IllegalArgumentException if the URL does not correspond to a file. */ publicstatic File urlToFile(final String url) { Stringpath= url; if (path.startsWith("jar:")) { // remove "jar:" prefix and "!/" suffix finalintindex= path.indexOf("!/"); path = path.substring(4, index); } try { if (PlatformUtils.isWindows() && path.matches("file:[A-Za-z]:.*")) { path = "file:/" + path.substring(5); } returnnewFile(newURL(path).toURI()); } catch (final MalformedURLException e) { // NB: URL is not completely well-formed. } catch (final URISyntaxException e) { // NB: URL is not completely well-formed. } if (path.startsWith("file:")) { // pass through the URL as-is, minus "file:" prefix path = path.substring(5); returnnewFile(path); } thrownewIllegalArgumentException("Invalid URL: " + url); }
Вы можете найти эти методы в общей библиотеке SciJava: