Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java: How to load Class stored as byte[] into the JVM?

Tags:

If one has serialized the entire .class file into byte[], and assuming the name of the class is known (passed along with the byte[]), how do you convert byte[] -> Class -> then load it to the JVM so that I could later use it by calling the Class.forName()?

NOTE: I'm doing this because I sent the .class over to another host, and the host's JVM doesn't know about this .class.

like image 517
sivabudh Avatar asked Nov 23 '09 04:11

sivabudh


People also ask

How do I load a class into JVM?

loadClass(String name, boolean resolve): This method is used to load the classes which are referenced by the JVM. It takes the name of the class as a parameter. This is of type loadClass(String, boolean). defineClass(): The defineClass() method is a final method and cannot be overriden.

What is class for byte [] in Java?

Byte class is a wrapper class for the primitive type byte which contains several methods to effectively deal with a byte value like converting it to a string representation, and vice-versa. An object of Byte class can hold a single byte value. Byte class offers four constants in the form of Fields.

Which loads .class file into JVM?

System Class Loader. The system or application class loader, on the other hand, takes care of loading all the application level classes into the JVM. It loads files found in the classpath environment variable, -classpath, or -cp command line option. It's also a child of the extensions class loader.


4 Answers

I'm actually using something like this right now in a test to give a set of Class definitions as byte[] to a ClassLoader:

  public static class ByteClassLoader extends URLClassLoader {     private final Map<String, byte[]> extraClassDefs;      public ByteClassLoader(URL[] urls, ClassLoader parent, Map<String, byte[]> extraClassDefs) {       super(urls, parent);       this.extraClassDefs = new HashMap<String, byte[]>(extraClassDefs);     }      @Override     protected Class<?> findClass(final String name) throws ClassNotFoundException {       byte[] classBytes = this.extraClassDefs.remove(name);       if (classBytes != null) {         return defineClass(name, classBytes, 0, classBytes.length);        }       return super.findClass(name);     }    } 
like image 155
Alex Miller Avatar answered Oct 06 '22 00:10

Alex Miller


Use the defineClass(String, byte[], int, int) method from ClassLoader

like image 35
Matt Avatar answered Oct 06 '22 00:10

Matt


Extend ClassLoader and then implement the necessary call to obtain your byte[] inside the method defineClass(). Conversely you can do this in findClass(). You'll thus load this ClassLoader at the beginning or employ it when you need class definitions via your array.

public class ByteArrayClassLoader extends ClassLoader {

    public Class findClass(String name) {
        byte[] ba = /* go obtain your byte array by the name */;

        return defineClass(name,ba,0,ba.length);
    }

}
like image 20
Jé Queue Avatar answered Oct 06 '22 02:10

Jé Queue


Okay, so here's what I did:

public class AgentClassLoader extends ClassLoader
{
  public void loadThisClass(ClassByte classByte_)
  {
    resolveClass(defineClass(classByte_.getName(),
                             classByte_.getBytes(),
                             0,
                             classByte_.getBytes().length));
  }
}

I hope that loads the class into JVM? If this really works, why didn't Java implementator make both defineClass and resolveClass public methods? I really wonder what they were thinking. Anyone can enlighten me?

Just for completeness, here's ClassByte

import java.io.Serializable;

public class ClassByte implements Serializable
{
  private String name;
  private byte[] bytes;

  ClassByte(String name_, byte[] bytes_)
  {
    name  = name_;
    bytes = bytes_;
  }

  public String getName()
  {
    return name;
  }

  public byte[] getBytes()
  {
    return bytes;
  }
}
like image 31
sivabudh Avatar answered Oct 06 '22 01:10

sivabudh