确定类来自哪个 JAR 文件

这并不是 odp.projodp.proj.test之间的特殊关系——它们只是碰巧被命名为明显相关。

如果 odp.proj.test包只是提供测试,那么您可以使用相同的包名(odp.proj)。Eclipse 和 Netbeans 等 IDE 将创建具有相同包名但具有 JUnit 语义的单独文件夹(src/main/java/odp/projsrc/test/java/odp/proj)。

我现在没有在 IDE 面前,只是在看 API 规范。

CodeSource src = MyClass.class.getProtectionDomain().getCodeSource();
if (src != null) {
URL jar = src.getLocation();
}

我想确定一个类来自哪个 JAR 文件。是这样做的吗?

103504 次浏览
访问修饰符仅仅是暗示性的(除非存在限制性的安全管理器)。

如果不将访问修饰符放在方法的前面,则可以说它是包私有的。
看下面的例子。

package odp.proj;
public class A
{
void launchA() { }
}


package odp.proj.test;
public class B
{
void launchB() { }
}


public class Test
{
public void test()
{
A a = new A();
a.launchA()    // cannot call launchA because it is not visible
}
}

龙目怪人 LiveInjector.java检查 LiveInjector.findPathJar()。请注意,在特殊情况下,文件实际上并不存在于 jar 中,您可能希望对其进行更改。

/**
* If the provided class has been loaded from a jar file that is on the local file system, will find the absolute path to that jar file.
*
* @param context The jar file that contained the class file that represents this class will be found. Specify {@code null} to let {@code LiveInjector}
*                find its own jar.
* @throws IllegalStateException If the specified class was loaded from a directory or in some other way (such as via HTTP, from a database, or some
*                               other custom classloading device).
*/
public static String findPathJar(Class<?> context) throws IllegalStateException {
if (context == null) context = LiveInjector.class;
String rawName = context.getName();
String classFileName;
/* rawName is something like package.name.ContainingClass$ClassName. We need to turn this into ContainingClass$ClassName.class. */ {
int idx = rawName.lastIndexOf('.');
classFileName = (idx == -1 ? rawName : rawName.substring(idx+1)) + ".class";
}


String uri = context.getResource(classFileName).toString();
if (uri.startsWith("file:")) throw new IllegalStateException("This class has been loaded from a directory and not from a jar file.");
if (!uri.startsWith("jar:file:")) {
int idx = uri.indexOf(':');
String protocol = idx == -1 ? "(unknown)" : uri.substring(0, idx);
throw new IllegalStateException("This class has been loaded remotely via the " + protocol +
" protocol. Only loading from a jar on the local file system is supported.");
}


int idx = uri.indexOf('!');
//As far as I know, the if statement below can't ever trigger, so it's more of a sanity check thing.
if (idx == -1) throw new IllegalStateException("You appear to have loaded this class from a local jar file, but I can't make sense of the URL!");


try {
String fileName = URLDecoder.decode(uri.substring("jar:file:".length(), idx), Charset.defaultCharset().name());
return new File(fileName).getAbsolutePath();
} catch (UnsupportedEncodingException e) {
throw new InternalError("default charset doesn't exist. Your VM is borked.");
}
}
private String resourceLookup(String lookupResourceName) {






try {


if (lookupResourceName == null || lookupResourceName.length()==0) {
return "";
}
// "/java/lang/String.class"


// Check if entered data was in java class name format
if (lookupResourceName.indexOf("/")==-1) {
lookupResourceName = lookupResourceName.replaceAll("[.]", "/");
lookupResourceName =  "/" + lookupResourceName + ".class";
}


URL url = this.getClass().getResource(lookupResourceName);
if (url == null) {
return("Unable to locate resource "+ lookupResourceName);


}


String resourceUrl = url.toExternalForm();


Pattern pattern =
Pattern.compile("(zip:|jar:file:/)(.*)!/(.*)", Pattern.CASE_INSENSITIVE);


String jarFilename = null;
String resourceFilename = null;
Matcher m = pattern.matcher(resourceUrl);
if (m.find()) {
jarFilename = m.group(2);
resourceFilename = m.group(3);
} else {
return "Unable to parse URL: "+ resourceUrl;


}


if (!jarFilename.startsWith("C:") ){
jarFilename = "/"+jarFilename;  // make absolute path on Linux
}


File file = new File(jarFilename);
Long jarSize=null;
Date jarDate=null;
Long resourceSize=null;
Date resourceDate=null;
if (file.exists() && file.isFile()) {


jarSize = file.length();
jarDate = new Date(file.lastModified());


try {
JarFile jarFile = new JarFile(file, false);
ZipEntry entry = jarFile.getEntry(resourceFilename);
resourceSize = entry.getSize();
resourceDate = new Date(entry.getTime());
} catch (Throwable e) {
return ("Unable to open JAR" + jarFilename + "   "+resourceUrl +"\n"+e.getMessage());


}


return "\nresource: "+resourceFilename+"\njar: "+jarFilename + "  \nJarSize: " +jarSize+"  \nJarDate: " +jarDate.toString()+"  \nresourceSize: " +resourceSize+"  \nresourceDate: " +resourceDate.toString()+"\n";




} else {
return("Unable to load jar:" + jarFilename+ "  \nUrl: " +resourceUrl);


}
} catch (Exception e){
return e.getMessage();
}




}
Ocal 文件系统,将找到该 jar 文件的绝对路径。

使用

String path = <Any of your class within the jar>.class.getProtectionDomain().getCodeSource().getLocation().getPath();
*

如果它包含多个条目,那么执行一些子字符串操作。

*@param 上下文将找到包含表示此类的类文件的 jar 文件。指定{@code null }让{@code LiveInjector } 找到属于自己的罐子 * 。

对于 Linux,我使用一个小脚本来帮助我找到可以在 find -exec中使用的 jar 类:

返回文章页面

unzip -l "$1" 2>/dev/null | grep $2 >/dev/null 2>&1 && echo "$1"
*@throw IllegalStateException 如果指定的类是从目录或其他方式(例如通过 HTTP、从数据库或其他方式)加载的,则抛出

基本上,因为 jar 是 zip,所以 unzip -l将打印类资源列表,所以您必须将 .转换为 /。您可以使用 tr在脚本中执行替换,但是在调用脚本时自己执行替换并不太麻烦。

* 其他自订类别载入装置)。 */

其思想是在类路径的根上使用 find来定位所有 jar,然后在所有找到的 jar 上运行 findclass.sh来查找匹配。

Public static String findPathJar (Class < ? > context)抛出 IllegalStateException {

它不能处理多个目录,但是如果仔细选择根目录,就可以让它工作。

如果(context = = null) context = LiveInjector.class;

现在,查找包含 org.apache.commons.lang3.RandomUtils类的 jar,以便让您的项目不再美化(...) :

$ find ~/.m2/repository/ -type f -name '*.jar' -exec findclass.sh {} org/apache/commons/lang3/RandomUtils \;


.m2/repository/org/apache/commons/commons-lang3/3.7/commons-lang3-3.7.jar
.m2/repository/org/apache/commons/commons-lang3/3.6/commons-lang3-3.6.jar
.m2/repository/org/apache/commons/commons-lang3/3.6/commons-lang3-3.6-sources.jar
$