我有一個任務來檢查一組來自classpath的未知類的條件。我想掃描它的類,加載他們每個人,並執行我的檢查。現在,我有一組URL用於類文件,並嘗試使用URLClassLoader。但要加載一個類,我需要指定一個完全限定的類名,但我沒有它們(我只有文件路徑)。我不認爲從類文件路徑構建類名是可以解決的,它是一個更好的方法嗎?從一組文件中加載類
謝謝!
我有一個任務來檢查一組來自classpath的未知類的條件。我想掃描它的類,加載他們每個人,並執行我的檢查。現在,我有一組URL用於類文件,並嘗試使用URLClassLoader。但要加載一個類,我需要指定一個完全限定的類名,但我沒有它們(我只有文件路徑)。我不認爲從類文件路徑構建類名是可以解決的,它是一個更好的方法嗎?從一組文件中加載類
謝謝!
我只是解析類文件的開始,尋找「包」關鍵字和第一次出現的「類」關鍵字。然後,當你結合這兩個(packageName + "." + className
)時,它應該導致適當的類名稱。
PiotrSliwa,感謝您的想法。最後,我使用commons-bcel庫來解析.class文件,它有點簡單。 – dbf
我啓動了一個項目,一旦自動測試運行時異常的類路徑中找到類,通過調用構造函數和方法與反思狡猾的參數,像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;
}
你可能不得不剝離一些代碼,並報告等
爲什麼從類文件路徑構建類名稱不可靠?我覺得是這樣的。我看到的唯一問題是內部類(一個類文件中有多個類)。那就是問題所在。 – Aleksandar
我的Win桌面上有類似於C:\ Projects \ my_project_trunk \ module \ target \ classes \ com \ a \ b \ c \ d \ e \ f \ Smth.class和/ home/user/teamcity/agent1 /.../a/b/c/d/e/f/Smth.class在構建服務器,所以我的解析器應該找到'類'部分,構建包名等。有趣的是,爲什麼我們不能從類文件中獲取類名,它應該在那裏... – dbf
我只是解析類文件的開始,尋找「包」關鍵字和第一次出現的「類」關鍵字。然後,當你結合這兩個(packageName +「。」+ className)時,它應該產生一個合適的類名。 – PiotrSliwa