CodeBlind
CodeBlind

Reputation: 4567

How do you obtain a class definition byte[] for array classes?

I'm trying to understand how the Java class loader works, specifically the defineClass(String,byte[],int,int) method. Let's say I want to load the class definition for NonIntrinsicType. I know I can find the *.class file for NonIntrinsicType, serialize its contents into a byte[] called bytes, and then call defineClass(null,bytes,0,bytes.length).

The weird situation I'm having trouble understanding is, how can I get a byte[] for the class definition of something like [LNonIntrinsicType - in other words, if my application requests the class definition for an instance of NonIntrinsicType[], I don't have a *.class file that corresponds to this class type. How would I obtain a byte[] for this type's definition?

You're probably wondering why I want to do this. I'm basically trying to create a network class loader, with a "Local" JVM that has class definitions on its class path, and a "Remote" JVM that does not have the aforementioned class definitions on its class path. "Remote" is encountering an instance of NonIntrinsicType[] and requests a definition from "Local" for that class type, but my "Local" JVM can't find a class file for NonIntrinsicType[], so it fails to provde a class definition byte[] to "Remote".

Added 9/7/2010

One thing I should have mentioned... I am using Socket and ObjectInputStream to receive messages sent to "Remote" by "Local". I've created a custom extension of ObjectInputStream on the "Remote" side and overrode protected Class<?> resolveClass(ObjectStreamClass). This is the first notification my "Remote" JVM gets when an incoming message contains instances of classes that have yet to be loaded. I have another socket that I use to pass class definitions around with, so when the first socket receives an instance of a class that hasn't been loaded, it requests a definition for that class from the "Local" JVM via the second socket.

The problem happens when my custom ObjectInputStream.resolveClass(ObjectStreamClass) gets passed an ObjectStreamClass that returns a class name for an array type (the name looks like [Lsome.ClassName;). I can easily parse out the base-level type some.ClassName and load it first - this is done in the call to NetworkClassLoader.getInstance.loadClass(), where I get a byte[] for the base-level class and then use it to call defineClass() inside that method call.

I understand now that you probably can't get a byte[] for an array type's class definition, so that leaves me trying to figure out how to find the Class<?> instance for the array type and return it. Here's the code for my resolveClass method in my custom ObjectInputStream on the "Remote" JVM's message-receiving Socket:

@Override
protected Class<?> resolveClass(ObjectStreamClass osc) 
        throws IOException, ClassNotFoundException{
    try {
        return super.resolveClass(osc);
    } catch (Exception e){}

    String name = osc.getName();
    boolean array = name.contains("[L");

    if(array) name = name.replace("[L","").
            replace("[","").replace(";","");

    Class<?> c = NetworkClassLoader.getInstance().loadClass(name);
    if(!array) return c;

    //If it's an array type, how do I obtain its corresponding
    //Class<?> and return it here?

    throw new ClassNotFoundException();
}

Upvotes: 2

Views: 8064

Answers (5)

Mihai Danila
Mihai Danila

Reputation: 2348

This excerpt from the ClassLoader javadoc:

Class objects for array classes are not created by class loaders, but are created automatically as required by the Java runtime. The class loader for an array class, as returned by Class.getClassLoader() is the same as the class loader for its element type; if the element type is a primitive type, then the array class has no class loader.

It would be interesting to understand how your classloader gets asked to create a class for [LNonIntrinsicType. It feels like you're doing something custom. If you could describe in more detail what you're doing, we could better understand your problem. What is the call stack when your class loader is asked to define [LNonIntrinsicType?

Upvotes: 0

Alexei Kaigorodov
Alexei Kaigorodov

Reputation: 13535

Array classes are created by JVM without calling defineClass().

See http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-5.html#jvms-5.3.3

Upvotes: 0

bmargulies
bmargulies

Reputation: 100196

You don't control the loading of arrays, because they aren't loaded. There's nothing to load. There's no class for an array. There's no class definition. There's no byte[].

Upvotes: 2

md_5
md_5

Reputation: 630

The only way this can be done is to patch your JVM's defineClass(...) method to look for the class(es) you want and then store them for later use.

Upvotes: 0

Jeffrey
Jeffrey

Reputation: 44808

You shouldn't need to create a definition for [LType. If you have a Class, you can create an array of that class with reflection:

Object array = Array.newInstance(yourClass, dimensions);

Upvotes: 4

Related Questions