gpt4 book ai didi

java - 以编程方式确定不需要导入的 JRE 类列表

转载 作者:塔克拉玛干 更新时间:2023-11-02 20:06:16 26 4
gpt4 key购买 nike

我需要以编程方式找出哪些 JRE 类可以在编译单元中引用而无需导入(用于静态代码分析)。我们可以忽略包本地类。 According to the JLS ,包 java.lang 中的类被隐式导入。输出应该是 binary class names 的列表.该解决方案应适用于纯 Java 5 及更高版本(无 Guava、Reflections 等),并且与供应商无关。

欢迎使用任何可靠的基于 Java 的解决方案。


以下是我迄今为止尝试过的一些注意事项:

乍一看,问题似乎可以归结为“如何从一个包中加载所有类?”,这当然实际上是不可能的,尽管存在一些解决方法(例如 thisthis ,加上那里链接的博客文章)。但我的情况要简单得多,因为不存在多个类加载器问题。 java.lang 东西总是可以被系统/引导类加载器加载,你不能在那个包中创建你自己的类。问题是,系统类加载器不会泄露链接的应用程序所依赖的类路径。

到目前为止,我还没有设法访问系统类加载器的类路径,因为在我使用的 HotSpot VM 上,Object.class.getClassLoader() 返回 null ,和Thread.currentThread().getContextClassLoader()可以委托(delegate)加载java.lang.Object,但本身不包含类路径。所以像 this one 这样的解决方案不要为我工作。此外,list of guaranteed system properties不包括具有此类类路径信息的属性(例如 sun.boot.class.path)。

如果我根本不必假设有 rt.jar 而是扫描系统类加载器使用的资源列表,那就太好了。对于特定于供应商的 JRE 实现,这种方法会更安全。

最佳答案

编译类似乎包含可读的 java/lang 文本。所以我写了一点代码看看是否可以提取这些导入。这是一个 hack,所以不可靠,但假设您可以提取/列出 jar 文件中的所有类,这可能是一个起点。

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;

public class Q21102294 {

public static final String EXTERNAL_JAR = "resources/appboot-1.1.1.jar";
public static final String SAMPLE_CLASS_NAME = "com/descartes/appboot/AppBoot.class";

public static HashSet<String> usedLangClasses = new HashSet<String>();

public static void main(String[] args) {

try {
Path f = Paths.get(EXTERNAL_JAR);
if (!Files.exists(f)) {
throw new RuntimeException("Could not find file " + f);
}
URLClassLoader loader = new URLClassLoader(new URL[] { f.toUri().toURL() }, null);
findLangClasses(loader, SAMPLE_CLASS_NAME);

ArrayList<String> sortedClasses = new ArrayList<String>();
sortedClasses.addAll(usedLangClasses);
Collections.sort(sortedClasses);
System.out.println("Loaded classes: ");
for (String s : sortedClasses) {
System.out.println(s);
}
} catch (Exception e) {
e.printStackTrace();
}

}

public static void findLangClasses(URLClassLoader loader, String classResource) throws Exception {

URL curl = loader.getResource(classResource);
if (curl != null) {
System.out.println("Got class as resource.");
} else {
throw new RuntimeException("Can't open resource.");
}
ByteArrayOutputStream bout = new ByteArrayOutputStream();
InputStream in = curl.openStream();
try {
byte[] buf = new byte[8192];
int l = 0;
while ((l = in.read(buf)) > -1) {
bout.write(buf, 0, l);
}
} finally {
in.close();
}
String ctext = new String(bout.toByteArray(), StandardCharsets.UTF_8);
int offSet = -1;
while ((offSet = ctext.indexOf("java/lang/", offSet)) > -1) {
int beginIndex = offSet;
offSet += "java/lang/".length();
char cnext = ctext.charAt(offSet);
while (cnext != ';' && (cnext == '/' || Character.isAlphabetic(cnext))) {
offSet += 1;
cnext = ctext.charAt(offSet);
}
String langClass = ctext.substring(beginIndex, offSet);
//System.out.println("adding class " + langClass);
usedLangClasses.add(langClass);
}
}

}

给出以下输出:

Got class as resource.
Loaded classes:
java/lang/Class
java/lang/ClassLoader
java/lang/Exception
java/lang/Object
java/lang/RuntimeException
java/lang/String
java/lang/StringBuilder
java/lang/System
java/lang/Thread
java/lang/Throwable
java/lang/reflect/Method

所用编译类的源代码可用here .

关于java - 以编程方式确定不需要导入的 JRE 类列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21102294/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com