从库 jar 中获取执行位置

get the execution location from within a library jar

我有一个名为 Utils 的 class,它有一个应该确定执行位置的静态方法。

public class Utils {
   public static Path getExecutionLocation() throws URISyntaxException {
     return Paths.get(Utils.class.getProtectionDomain().getCodeSource().getLocation().toURI());
   }
}

在 Eclipse 中,这给了我:C:\Users\USERNAME\workspace\PROJECT\bin\main\

运行 作为一个罐子,这给了我:C:\PATH\TO\JAR\thatJar.jar

两者都正确且符合预期。

现在我在一个名为 someLib.jar 的库中有了 Utils class。 当我在另一个项目中使用该库时,如果我为该项目构建一个内部包含 someLib.jar 的 jar,它就可以工作。 但在 Eclipse 中,它 return 是通往 someLib.jar.

的路径

我要return项目执行目录的路径: C:\Users\USERNAME\workspace\A_PROJECT_USING_SOMELIB\bin\main\

我试过了

return new File(ClassLoader.getSystemClassLoader().getResource(".").getPath()).toPath();

但是在 jar 中失败了,因为 getResource(".") 导致 null

我可以从项目内部给 getExecutionLocation 一个 class 作为参数并在其上执行 getProtectionDomain()。但是我想在这里问问有没有人知道更好的解决办法。

试试这个:

public class Utils {
   public static Path getExecutionLocation(Class c) throws URISyntaxException {
        return Paths.get(c.getProtectionDomain().getCodeSource().getLocation().toURI());
    }
}

所以你将 class 作为参数传递给函数。例如:

public class Main
    {
        public static void main(String[] args)
        {
            Utils.getExecutionLocation(Main.class);
        }
    }

请注意,可能有更直接的解决方案, 但这是我第一个想到的,我想,为什么不呢:)

我找到了一个基于 ClassLoader.getSystemClassLoader() 方法的解决方案,该方法为我提供了 class 加载程序,该加载程序负责使用 someLib.jar.[=14 的项目的主要入口点=]

在 IDE 中,我可以使用 getResource(".") 获取所有资源(和来源)的根路径 URL。

从 jar 文件这不起作用。所以我使用 getResource("META-INF") 获取 META-INF 文件夹(里面有清单)的 URL 并且应该始终存在于 jar 文件中。

也许还不是最优的。但到目前为止我可以使用它。

public static Path getExecutionLocation() throws URISyntaxException, IOException {
    // System ClassLoader is on the highest level and responsible for the main entry point
    ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
    // get the resources root path (works within IDEs)
    URL executionLocation = systemClassLoader.getResource(".");
    // fallback for jars
    if(executionLocation == null) {
        // look for META-INF folder
        URL metaInfLocation = systemClassLoader.getResource("META-INF");
        // URL looks like "jar:file:/C:/path/to/jar/jarfile.jar!/META-INF"
        // openConnection on URL - does not really establish connection but checks if URL would be valid
        JarURLConnection connection = (JarURLConnection) metaInfLocation.openConnection();
        // extracts URL to jar file
        executionLocation = connection.getJarFileURL();
    }
    // impossible to determine
    if(executionLocation == null) throw new RuntimeException("Impossible to determine exeution location");
    
    return Paths.get(executionLocation.toURI());
}