我有一项任务是从类路径检查未知类集的一组条件。我想扫描它的类,加载它们并执行我的检查。现在我有一组类文件的URL,我尝试使用URLClassLoader。但是要加载一个类我需要指定一个完全限定的类名,但我没有它们(我只有文件路径)。我不认为从类文件路径构建类名是可以解除的,这是一种更好的方法吗?
谢谢!
答案 0 :(得分:3)
我只是解析类文件的开头,寻找" package"关键字和第一次出现" class"关键词。然后,当你将这两者(packageName + "." + className
)结合起来时,它应该产生一个合适的类名。
答案 1 :(得分:1)
我启动了一个项目,自动测试在类路径上找到的运行时异常类,通过使用null
,0
,1
等狡猾的参数反射调用构造函数和方法, -1
,""
等。
该项目有一个名为Finder的类,大致可以满足您的需求:
static List<Class<?>> findClassesForPackage(String packagename, Report report) throws ClassNotFoundException {
// 'classes' will hold a list of directories matching the package name.
// There may be more than one if a package is split over multiple
// jars/paths
List<Class<?>> classes = new ArrayList<Class<?>>();
List<File> directories = new ArrayList<File>();
try {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
if (classLoader == null) {
throw new ClassNotFoundException("Can't get class loader.");
}
// Ask for all resources for the path
String path = packagename.replace('.', '/');
Enumeration<URL> resources = classLoader.getResources(path);
while (resources.hasMoreElements()) {
URL res = resources.nextElement();
if (res.getProtocol().equalsIgnoreCase("jar")) {
JarURLConnection conn = (JarURLConnection) res.openConnection();
JarFile jar = conn.getJarFile();
for (JarEntry entry : Collections.list(jar.entries())) {
if (entry.getName().startsWith(path) && entry.getName().endsWith(".class")
&& !entry.getName().contains("$")) {
String className = entry.getName().replace("/", ".").substring(0,
entry.getName().length() - 6);
LOG.debug("Adding JAR className " + className);
try {
Class<?> clazz = Class.forName(className);
classes.add(clazz);
report.addClass(className);
} catch (Throwable throwable) {
ParamSet params = new ParamSet();
params.addParamValue(new ParamValue(className, "fully qualified classname"));
report.addError(className, new Error("Class.forName()", params, throwable));
}
}
}
} else
directories.add(new File(URLDecoder.decode(res.getPath(), "UTF-8")));
}
} catch (NullPointerException e) {
throw new ClassNotFoundException(String.format("%s does not appear to be a valid package", packagename), e);
} catch (UnsupportedEncodingException e) {
throw new ClassNotFoundException(String.format("%s does not appear to be a valid package", packagename), e);
} catch (IOException e) {
throw new ClassNotFoundException(String.format("Could not get all resources for %s", packagename), e);
}
List<String> subPackages = new ArrayList<String>();
// For every directory identified capture all the .class files
for (File directory : directories) {
if (directory.exists()) {
// Get the list of the files contained in the package
File[] files = directory.listFiles();
for (File file : files) {
// add .class files to results
String fileName = file.getName();
if (file.isFile() && fileName.endsWith(".class")) {
// removes the .class extension
String className = packagename + '.' + fileName.substring(0, fileName.length() - 6);
LOG.debug("Adding FILE className " + className);
try {
Class<?> clazz = Class.forName(className);
classes.add(clazz);
report.addClass(className);
} catch (Throwable throwable) {
ParamSet params = new ParamSet();
params.addParamValue(new ParamValue(className, "fully qualified classname"));
report.addError(className, new Error("Class.forName()", params, throwable));
}
}
// keep track of subdirectories
if (file.isDirectory()) {
subPackages.add(packagename + "." + fileName);
}
}
} else {
throw new ClassNotFoundException(String.format("%s (%s) does not appear to be a valid package",
packagename, directory.getPath()));
}
}
// check all potential subpackages
for (String subPackage : subPackages) {
classes.addAll(findClassesForPackage(subPackage, report));
}
return classes;
}
您可能必须删除一些执行报告等的代码。