Is it possible to have the System ClassLoader load .class files specified at run time?

后端 未结 6 966
[愿得一人]
[愿得一人] 2021-01-01 00:09

I am writing a static analysis tool for an assignment, it analyses Java bytecode using the ASM library. One of the parts of ASM that we use requires (or at least, appears to

相关标签:
6条回答
  • 2021-01-01 00:44

    You can't, as far as I know, extend the System class loader at runtime, but you can dynamically load classes from an arbitrary location (jar or directory) using URLClassLoader.

    0 讨论(0)
  • 2021-01-01 00:46

    First of all, ASM can be used in a such way that it won't use ClassLoader to obtain information about classes.

    There are several places in ASM framework where it loads classes by default but all those places can be overridden in your own subclasses. Out of the top of my head:

    • ClassWriter.getCommonSuperClass() method is called only when ClassWriter.COMPUTE_FRAMES flag is used and can be overwriten to not use ClassLoader to get inforamtion about classes. You can find an example of that in ClassWriterComputeFramesTest that introduces a ClassInfo abstraction
    • Similarly SimpleVerifier.getClass() method is used by SimpleVerifier.isAssignableFrom() and you can overwrite the latter and use the ClassInfo abstraction to find the common super type. If I am not mistaken, AspectWerkz project had implemented similar thing in its type pattern matching code. Also note that there is SimpleVerifier.setClassLoader() method, which you can use if you still want to load your own classes.

    On a side note, on a Sun's JVMs, loaded classes gets to PermGen area and can't be unloaded, so it is not a good idea to load classes only for static code analysis purposes if you can avoid that, especially if tool would be integrated into a long-live process, such as IDE.

    0 讨论(0)
  • 2021-01-01 00:48

    You could try to setup a "launcher" in the startup of your application that creates an URLClassLoader passing it the locations on the classpath and your own .class locations and start the application from that classloader.

    When the SimpleVerifier is loaded by the URLClassLoader it will also be able to load the classes from the extra locations.

    0 讨论(0)
  • 2021-01-01 00:59

    I created my own ClassLoader its quite simple.

     /**
     * Used to hold the bytecode for the class to be loaded.
     */
    private final static ThreadLocal<byte[]> BYTE_CODE = new ThreadLocal<byte[]>();
    
    @Override
    protected Class<?> findClass(final String name) throws ClassNotFoundException {
        final byte[] bytes = BYTE_CODE.get();
        if (null == bytes) {
            throw new ClassNotFoundException(name);
        }
        return this.defineClass(null, bytes, 0, bytes.length);
    }
    
    0 讨论(0)
  • 2021-01-01 01:05

    Almost.

    If you have classes compiled somewhere, you can load them with a URLClassLoader. You can then set this ClassLoader to be the ClassLoader for the current Thread: Thread.setContextClassLoader(ClassLoader)

    Users can that get the current threads context class loader and use that to access the class definition.

    0 讨论(0)
  • 2021-01-01 01:07

    Yes, you can use URLClassLoader

    I have a test where I do load the class at runtime. This class is not in the classpath (nor even exist when the test is run for that matter ), later is it loaded and works great.

    Here's the code.

    void testHello() throws MalformedURLException, ClassNotFoundException {
        URL[] url = {
                new URL("file:/home/oreyes/testwork/")
        };
    
        try {
            new URLClassLoader(url).loadClass("Hello");
            throw new AssertionError("Should've thrown ClassNotFoundException");
        } catch ( ClassNotFoundException cnfe ){}
    
    
        c.process();// create the .class file 
    
        new URLClassLoader(url).loadClass("Hello");
    
        // it works!!
    }
    

    Taken from this question.

    0 讨论(0)
提交回复
热议问题