我正在创建一个包含我使用wsimport生成的类的包,现在我正在尝试加载它以供使用,我该怎么做?原生?或者像byte-buddy这样的lib,我尝试了波纹管代码来加载包中的每个类:
File [] files = new File("<Path to package in filesystem with classes (*.class)>").listFiles();
List<URL> classUrls = new ArrayList<>();
for(File file : files) {
classUrls.add(new URL("file://" + file.getAbsolutePath()));
}
URL[] classz = new URL[classUrls.size()];
classz = classUrls.toArray(classz);
URLClassLoader child = new URLClassLoader(classz);
Class.forName("com.abc.external.resources.genwn239aqyhmfz.SomeClass", true, child);
但我仍然得到(包:com.abc.external.resources.genwn239aqyhmfz.SomeClass)
java.lang.ClassNotFoundException: com.abc.external.resources.genwn239aqyhmfz.SomeClass
答案 0 :(得分:2)
类路径的规则与启动应用程序时必须遵守的规则没有区别。类路径条目是不是类文件,也不是包含它们的目录,而是包结构的根。
因此,如果要加载的类是com.abc.external.resources.genwn239aqyhmfz.SomeClass
,则类路径条目必须是包含com
目录的目录,其中包含abc
目录,依此类推。如果您知道其中一个类的预期完全限定名称,则很容易找到正确的目录。只需遍历文件层次结构,因为限定名称具有包组件。但是,如果您事先不知道名称,找到它可能会很棘手。这是一幅草图:
// pass the expected name of one class contained in f or null if not known
static void loadClasses(File f, String predictedName)
throws IOException, ClassNotFoundException {
File[] classes = f.listFiles((d,n)->n.endsWith(".class"));
if(classes == null || classes.length == 0) {
System.err.println("no classes or not a directory");
return;
}
if(predictedName == null) predictedName = predictName(classes[0]);
for(int p = predictedName.indexOf('.'); p >= 0; p = predictedName.indexOf('.', p+1))
f = f.getParentFile();
URLClassLoader classLoader = new URLClassLoader(new URL[] { f.toURI().toURL() });
String packageName = predictedName.substring(0, predictedName.lastIndexOf('.')+1);
for(File cf: classes) {
String name = cf.getName();
name = name.substring(0, name.length()-6); // strip off ".class"
Class<?> cl = classLoader.loadClass(packageName+name);
// what do you wanna do with the classes?
System.out.println(cl);
}
}
private static String predictName(File classFile) throws IOException {
byte[] data = Files.readAllBytes(classFile.toPath());
return new ClassLoader() {
String getName() {
return defineClass(null, data, 0, data.length).getName();
}
}.getName();
}
predictName
实现非常简单。如果该类依赖于JVM立即尝试解析的同一文件层次结构中的类,则它将失败,因为我们还没有必要的信息。在这种情况下,只有字节码解析库允许在不加载类的情况下提取名称将有所帮助。但这超出了这个问题的范围......