加载包和内部类 [英] Load a package and inside classes
问题描述
我正在使用一个由wsimport即时生成的类创建一个包,现在我正试图加载它以使用,我该怎么做?本机?或像字节伙伴这样的lib,我尝试了下面的代码将每个类加载到包中:
I'm creating a package with some classes that I generated with wsimport on the fly and now I'm trying to load it to use, how can I do this? natively? or with some lib like byte-buddy, I tried the bellow code to load each class in a package:
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)
But I still getting (Package: com.abc.external.resources.genwn239aqyhmfz.SomeClass)
java.lang.ClassNotFoundException: com.abc.external.resources.genwn239aqyhmfz.SomeClass
推荐答案
类路径的规则与启动应用程序时必须遵循的规则没有什么不同.类路径条目不是 类文件,也不是包含它们的目录,而是包结构的根.
The rules for the class path are not different to the rules you have to obey when launching your application. The class path entries are not class files nor directories containing them, but the roots of your package structure.
因此,如果要加载的类是com.abc.external.resources.genwn239aqyhmfz.SomeClass
,则类路径条目必须是包含com
目录的目录,该目录包含abc
目录,依此类推.如果您知道其中一个类别的预期全限定名称,则可以轻松找到正确的目录.只需遍历文件层次结构多次,只要合格名称具有包组件即可.但是,如果您事先不知道名称,发现它可能很棘手.这是一个草图:
So if the class you want to load is com.abc.external.resources.genwn239aqyhmfz.SomeClass
, the class path entry has to be the directory containing the com
directory, which contains the abc
directory, and so on. If you know the expected full qualified name of one of the classes, it’s easy to find the right directory. Just traverse to the file hierarchy up as many times as the qualified name has package components. However, when you don’t know the name beforehand, finding it can be tricky. Here is a sketch:
// 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立即尝试解析的相同文件层次结构中的类的依赖关系,则该类将失败,因为我们尚无必要的信息.在这种情况下,只有字节码解析库允许提取名称而无需加载类才有帮助.但这超出了这个问题的范围...
The predictName
implementation is a very simple one. If the class has dependencies to classes within the same file hierarchy which the JVM immediately tries to resolve, it will fail as we don’t have the necessary information yet. In that case, only a bytecode parsing library allowing to extract the name without loading the class would help. But that exceeds the scope of this question…
这篇关于加载包和内部类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!