加载包和内部类

时间:2017-11-14 14:30:30

标签: class java-8 byte-buddy

我正在创建一个包含我使用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

1 个答案:

答案 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立即尝试解析的同一文件层次结构中的类,则它将失败,因为我们还没有必要的信息。在这种情况下,只有字节码解析库允许在不加载类的情况下提取名称将有所帮助。但这超出了这个问题的范围......