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.