Load a package and inside classes

有些话、适合烂在心里 提交于 2020-05-26 09:32:10

问题


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);

But I still getting (Package: com.abc.external.resources.genwn239aqyhmfz.SomeClass)

java.lang.ClassNotFoundException: com.abc.external.resources.genwn239aqyhmfz.SomeClass

回答1:


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.

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();
}

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…



来源:https://stackoverflow.com/questions/47288250/load-a-package-and-inside-classes

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!