Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Send an Anonymous class over sockets? (Object..Stream in Java)

So right now, I have a server that is running with ObjectInputStream and ObjectOutputStream.

The problem I am having is that I have a custom (anonymous) class that extends java.lang.Date that I am trying to send to the client and then compile.

So nowhere do I ever define the class on the client side, but I want to compile the class programmatically. I have tried many different methods, but every time I get a ClassNotFoundException because the class isn't on the client side initially.

Class<?> dateClass = (Class<?>) in.readObject(); //This is where the CNF Exception occurs
Compiler.compileClass(dateClass);
like image 703
Avogadro Avatar asked Feb 25 '12 23:02

Avogadro


1 Answers

The Java Serialization mechanism assumes the classes are known to the deserializing JVM, it doesn't send the class definitions. In particular, when you serialize a Class object, you don't send the byte code for that class but only instruct the receiving VM to look up the Class object for a class with a particular name.

Also note that a Class object represents a class defined in the JVM, i.e. the class' bytecode has already been loaded. It makes little sense to try to compile to class to generate that bytecode after loading the class.

So, we need to somehow get the class definition to the client. The easiest approach is to do this like any other class the client needs (by packing it in the client's jar file, or whatever means you use to install the client programm). If that is not possible, you could load the class definition over the network, for instance by using a URLClassLoader, or you could send the classfile through the serialization stream, and upon receiving it on the client use ClassLoader.defineClass to load the class.

PS: This issue is completely indepedent of whether the class is named or not. The following test code shows that objects of anonymous classes can be serialized and deserialized just fine (if the receiving VM has the class definition):

    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    try (ObjectOutputStream oos = new ObjectOutputStream(baos)) {
        Serializable payload = new Serializable() {
            @Override
            public String toString() {
                return "hello from the anonymous class";
            }
        };
        oos.writeObject(payload);
        oos.writeObject(payload.getClass());
    }

    try (ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()))) {
        System.out.println(in.readObject());
        System.out.println(in.readObject());
    }
like image 170
meriton Avatar answered Nov 03 '22 20:11

meriton