Using URLClassLoader to load .class file

我只是一个虾纸丫 提交于 2021-02-05 05:55:05

问题


I'm aware that this question has been asked before:

How to use URLClassLoader to load a *.class file?

However I don't really understand due to the lack of example. I'm currently working on a project and trying to load user-given .class objects which can be located in any directories on the machine.

//Create URL to hash function class file
URL url_hashFunctionPath = new URL("file:///" + _sHashFunctionFilePath);

//Packet URL to a URL array to be used by URLClassLoader
URL[] urlA_hashFunctionPath = {url_hashFunctionPath};

//Load URL for hash function via a URL class loader
URLClassLoader urlCl_hashFunctionClassLoader = new URLClassLoader(urlA_hashFunctionPath);

//Load user hash function into class to initialize later (TEST: HARD CODE FOR NOW)
m_classUserHashClass = urlCl_hashFunctionClassLoader.loadClass(_sUserHashClassName);

The last line gave me a ClassNotFoundException, from my experiment & understanding the user-given class function has to be in the classpath?

PS: 1st time posting questions feel free to correct me where I did not follow the appropriate manner.

//SOLUTION

The solution that I arrived at with the generous help of [WillShackleford][1], this solution can load the a .class file in a given filepath. For more information refer to code and their given comments.

//The absolute file path to the class that is to be loaded (_sHashFunctionFilePath = absolute file path)
String pathToClassFile = _sHashFunctionFilePath;
System.out.println("File to class: " + _sHashFunctionFilePath);

//Declare the process builder to execute class file at run time (Provided filepath to class)
ProcessBuilder pb = new ProcessBuilder("javap", pathToClassFile);
try
{
    //Start the process builder
    Process p = pb.start();

    //Declare string to hold class name
    String classname = null;
    //Declare buffer reader to read the class file & get class name
    try(BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream())))
    {
        String line;
        while(null != (line = br.readLine()))
        {
            if(line.startsWith("public class"))
            {
                classname = line.split(" ")[2];
                break;
            }
        }
        System.out.println("classname = " + classname);
    }
    catch(IOException _error)
    {

    }

    //Declare file path to directory containing class to be loaded
    String pathToPackageBase = pathToClassFile.substring(0, pathToClassFile.length() - (classname + ".class").length());
    System.out.println("pathToPackageBase = " + pathToPackageBase);

    try
    {
        //Create class to hold the class to be loaded via a URL class loader
        Class clss = new URLClassLoader(
                new URL[]{new File(pathToPackageBase).toURI().toURL()}
        ).loadClass(classname);

        //Create ab object/instance of said class
        Object test = clss.newInstance();

        //Declare & create requested method from user hash function class (Method is work & takes no arguments)
        Method method = clss.getMethod("work", null);
        method.invoke(test, null);
    }

回答1:


In the directory /home/shackle/somedir/classes/pkg I have a file Test.class created from a java file with package pkg; eg :

package pkg;

public class Test {

    public String toString() {
        return "secret_string";
    }
}

Then I load it with :

System.out.println(new URLClassLoader(
        new URL[]{new File("/home/shackle/somedir/classes").toURI().toURL()}
).loadClass("pkg.Test").newInstance().toString());

Notice that I do not put the pkg/Test in the URL string but the load class argument has the pkg. prefix.

You can get the class name directly from the file like this:

Class clsReaderClss = ClassLoader.getSystemClassLoader().loadClass("jdk.internal.org.objectweb.asm.ClassReader");
System.out.println("clsReaderClss = " + clsReaderClss);
Constructor con = clsReaderClss.getConstructor(InputStream.class);
Object reader = con.newInstance(new FileInputStream(directFile));
Method m = clsReaderClss.getMethod("getClassName");
String name = m.invoke(reader).toString().replace('/', '.');
System.out.println("name = " + name);

An alternative that doesn't require access to internal classes.

String pathToClassFile = "/home/shackle/somedir/classes/pkg/Test.class";
ProcessBuilder pb = new ProcessBuilder("javap",pathToClassFile);
Process p = pb.start();
String classname = null;
try(BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()))) {
   String line;
   while(null != (line = br.readLine())) {
       if(line.startsWith("public class")) {
           classname = line.split(" ")[2];
           break;
       }
   }
}
System.out.println("classname = " + classname);

Class can then be loaded with:

String pathToPackageBase = pathToClassFile.substring(0, pathToClassFile.length() - (classname + ".class").length());
System.out.println("pathToPackagBase = " + pathToPackageBase);
Class clss = new URLClassLoader(
        new URL[]{new File(pathToPackageBase).toURI().toURL()}
).loadClass(classname);
System.out.println(clss.newInstance().toString());



回答2:


Your _sHashFunctionFilePath needs to have the package name of the target class removed from it, so the ClassLoader will look in _sHashFunctionFilePath + package.name + HashFunction.class as the path to the file. If you don't do that, the ClassLoader won't be able to find the file.

So if the target class is my.great.HashFunction in HashFunction.class, then it needs to be in a directory called my/great/ if you want to use URLClassLoader. Then, you'd use /path/to as the file:/// URL for your URLClassLoader if the .class file was actually found in /path/to/my/great/HashFunction.class.



来源:https://stackoverflow.com/questions/32771096/using-urlclassloader-to-load-class-file

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