我需要从ClassPath上的Jar文件中获取所有类,我使用了这篇文章作为我的解决方案。当我将路径设置为包名时,本文中的方法可以工作,但如果包位于Jar文件中则不起作用。
在评论下面,人们发布了他们声称可以用于Jar文件的代码(他们修改了文章的代码)。我看过他们的代码,它似乎应该工作,它确实适用于jar文件中的而不是的包,但他们没有指定要传递什么作为参数,告诉包来自jar文件的方法。我已经试过了我能想到的所有组合,但都没用。
因此,对于Jar文件中而不是的包,这将是使用方法的工作方式, Class[] myClasses = getClassesInPackage("my.package.name", null);
它应该与Jar文件中的包一起工作,但我不知道该用什么代替"my.package.name"
。我试过只给出Jar文件上的包名,但它找不到任何东西。
我的想法是类似于"myJarName"
或"myJarName.my.package.name"
,但这些都不工作。
这里是完整的代码,
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Member;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.TreeSet;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import static java.lang.System.out;
public class ClassSpy {
public static void main(String... args) {
try {
Class[] myClasses = getClassesInPackage("you.package.name.here", null);
for(Class index: myClasses)
out.format("Class:%n %s%n%n", index.getCanonicalName());
}
catch (ArrayIndexOutOfBoundsException e) {
e.printStackTrace();
}
/**
* Scans all classes accessible from the context
* class loader which belong to the given package
* and subpackages. Adapted from
* http://snippets.dzone.com/posts/show/4831
* and extended to support use of JAR files
* @param packageName The base package
* @param regexFilter an optional class name pattern.
* @return The classes
*/
public static Class[] getClassesInPackage(String packageName, String regexFilter) {
Pattern regex = null;
if (regexFilter != null)
regex = Pattern.compile(regexFilter);
try {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
assert classLoader != null;
String path = packageName.replace('.', '/');
Enumeration<URL> resources = classLoader.getResources(path);
List<String> dirs = new ArrayList<String>();
while (resources.hasMoreElements()) {
URL resource = resources.nextElement();
dirs.add(resource.getFile());
}
TreeSet<String> classes = new TreeSet<String>();
for (String directory : dirs) {
classes.addAll(findClasses(directory, packageName, regex));
}
ArrayList classList = new ArrayList();
for (String clazz : classes) {
classList.add(Class.forName(clazz));
}
return (Class[]) classList.toArray(new Class[classes.size()]);
}
catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* Recursive method used to find all classes in a given path
* (directory or zip file url). Directories are searched recursively.
* (zip files are Adapted from http://snippets.dzone.com/posts/show/4831
* and extended to support use of JAR files @param path The base
* directory or url from which to search. @param packageName The package
* name for classes found inside the base directory @param regex an
* optional class name pattern. e.g. .*Test*
* @return The classes
*/
private static TreeSet findClasses(String path, String packageName, Pattern regex) throws Exception {
TreeSet classes = new TreeSet();
if (path.startsWith("file:") && path.contains("!")) {
String[] split = path.split("!");
URL jar = new URL(split[0]);
ZipInputStream zip = new ZipInputStream(jar.openStream());
ZipEntry entry;
while ((entry = zip.getNextEntry()) != null) {
System.out.println("Here 1");
if (entry.getName().endsWith(".class")) {
System.out.println("Here 2");
String className = entry.getName()
.replaceAll("[$].*", "")
.replaceAll("[.]class", "")
.replace('/', '.');
if (className.startsWith(packageName) && (regex == null
|| regex.matcher(className).matches()))
classes.add(className);
}
}
}
File dir = new File(path);
if (!dir.exists()) {
return classes;
}
File[] files = dir.listFiles();
for (File file : files) {
if (file.isDirectory()) {
assert !file.getName().contains(".");
classes.addAll(findClasses(file.getAbsolutePath()
, packageName + "." + file.getName()
, regex));
}
else if (file.getName().endsWith(".class")) {
String className = packageName + '.' + file
.getName()
.substring(0, file.getName().length() - 6);
if (regex == null || regex.matcher(className).matches())
classes.add(className);
}
}
return classes;
}
}
您应该能够复制所有代码并编译它(一些导入不会被使用,因为我只显示与问题相关的部分,而不是整个程序)。
对于工作演示,您可以将"my.package.name"
更改为类路径上的某个包。
Class[] myClasses = getClassesInPackage("my.package.name", null);
我以前从未使用过这个方法,如果我需要做你想做的事情,我会直接使用
Classname name = new Classname();