ClassLoader loading class using byte array

0

In this article, we will see how to convert a class in the form of a byte array into an instance of class Class.

Define ClassLoader

In order to load classes external to the system, we need to define our own class loader.
Below class ClassA is in path external/com/javarticles/classloader folder. We will convert the class into byte array and then define class using the byte array.

ClassA:

package com.javarticles.classloader;

public class ClassA {
    public String toString() {
        return "This is Class A";
    }
}

Our class loader extends ClassLoader. We overload defineClass() and pass class name to it. Based on class name and the external directory path, we read the class file, convert it into byte array and then call the ClassLoader’s defineClass() method to convert the byte array into an instance of Class object.

MyClassLoader:

package com.javarticles.classloader;

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

public class MyClassLoader extends ClassLoader {
    private final String externalDir;
    public MyClassLoader(final String externalDir) {
        this.externalDir =  System.getProperty("user.dir") + "/" + externalDir;
    }

    public void defineClass(final String fullClassName) throws IOException {
        String className = "/" + fullClassName.replaceAll("\\.", "/") + ".class";
        FileInputStream inputStream = new FileInputStream(externalDir + className);
        try {
            byte[] data = toByteArray( inputStream );
            defineClass(fullClassName, data, 0, data.length);
        } finally {
            inputStream.close();
        }
    }
    
    private byte[] toByteArray(InputStream inputStream) throws IOException {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int read;
        byte[] byteArray = new byte[1000];
        while ( (read = inputStream.read(byteArray, 0, byteArray.length) ) != -1) {
          out.write( byteArray, 0, read );
        }
        out.flush();
        return out.toByteArray();
    }
}

The class won’t be accessible by the SystemClassLoader as it is not in the classpath so any attempt to load the class using system classloader will fail. If we try loading the class without defining the class then again it fails as it is not able to find Class instance for the passed in class. In order to load successfully using the custom class loader, we first need convert the class file into bytes using custom class loader’s defineClass().

DefineClassFromBytesExample:

package com.javarticles.classloader;

import java.io.IOException;

public class DefineClassFromBytesExample {
    public static void main(String[] args) throws IOException,
            ClassNotFoundException, InstantiationException,
            IllegalAccessException, NoSuchMethodException, SecurityException {
        String fullClassName = "com.javarticles.classloader.ClassA";
        try {
            DefineClassFromBytesExample.class.getClassLoader().loadClass(
                    fullClassName);
        } catch (ClassNotFoundException e) {
            System.out
                    .println("System classloader cannot load as ClassA is not in classpath");
        }
        MyClassLoader myClassLoader = new MyClassLoader("external");
        Class<?> classA = null;
        try {
            classA = myClassLoader.loadClass(fullClassName);
        } catch (ClassNotFoundException e) {
            System.out.println("MyClassLoader cannot load as ClassA is not yet defined");
        }
        myClassLoader.defineClass(fullClassName);
        classA = myClassLoader.loadClass(fullClassName);
        Object o = classA.newInstance();
        System.out.println("ClassA.toString()=" + o);
    }
}

Output:

System classloader cannot load as ClassA is not in classpath
MyClassLoader cannot load as ClassA is not yet defined
ClassA.toString()=This is Class A

Download the source code

This was an example of defining and loading class when the class is available as byte array.

You can download the source code here: javadefineclassfrombytesexample.zip

About Author

Ram’s expertise lies in test driven development and re-factoring. He is passionate about open source technologies and loves blogging on various java and open-source technologies like spring.
You can reach him at [email protected]

Comments are closed.