Serializing and deserializing an object that does not implement Serializable

Motivation:

To aid in remote debugging (Java), it is useful to be able to ask remote servers to send to arbitrary objects on my local machine for testing. However, this means that the remote server must be able to serialize an arbitrary Java object that is not known in advance at runtime.

In particular, I would like to be able to serialize even those objects that do not implementSerializable

. I came across JBossSerialization which claimed that with JBossSerialization ...

... you can serialize classes that don't implement Serializable

Fine! Even better, I was able to find code that supposedly demonstrates how to do this .

Problem

So, grabbing the code from schabell.org , I wrote a quick test to check that I could serialize and deserialize without issue:

import org.jboss.serial.io.JBossObjectInputStream;
import org.jboss.serial.io.JBossObjectOutputStream;
import java.io.*;

class MyObj {   // Test class which doesn't implement Serializable
    public int x;
    MyObj(int x) {this.x = x;}
}

public class SerializationTest {

    public static void main(String[] args) {
        MyObj obj = new MyObj(1);
        byte[] byteArray = getByteArrayFromObject(obj);            // Try to serialize
        MyObj result = (MyObj) getObjectFromByteArray(byteArray);  // Try to deserialize
        System.out.println(result.x);
    }

    // Code that I pinched from website below (http://www.schabell.org/2009/03/jboss-serialization-simple-example.html):
    public static Object getObjectFromByteArray(byte[] bytes) {
        Object result = null;

        try {
            ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
            ObjectInputStream ois = new JBossObjectInputStream(bais);
            result = ois.readObject();   // ERROR HERE!!!
            ois.close();
        } catch (IOException ioEx) {
            ioEx.printStackTrace();
        } catch (ClassNotFoundException cnfEx) {
            cnfEx.printStackTrace();
        }

        return result;
    }

    public static byte[] getByteArrayFromObject(Object obj) {
        byte[] result = null;

        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new JBossObjectOutputStream(baos);
            oos.writeObject(obj);
            oos.flush();
            oos.close();
            baos.close();
            result = baos.toByteArray();
        } catch (IOException ioEx) {
            ioEx.printStackTrace();
        }

        return result;
    }
}

      

The problem is, the test failed. Debug indicated that I can only serialize, not deserialize. The call ois.readObject()

on line 26 is the culprit and gives as quality SerializationException

:

org.jboss.serial.exception.SerializationException: Could not create instance of MyObj - MyObj
    at org.jboss.serial.classmetamodel.ClassMetaData.newInstance(ClassMetaData.java:342)
    at org.jboss.serial.persister.RegularObjectPersister.readData(RegularObjectPersister.java:239)
    at org.jboss.serial.objectmetamodel.ObjectDescriptorFactory.readObjectDescriptionFromStreaming(ObjectDescriptorFactory.java:412)
    at org.jboss.serial.objectmetamodel.ObjectDescriptorFactory.objectFromDescription(ObjectDescriptorFactory.java:82)
    at org.jboss.serial.objectmetamodel.DataContainer$DataContainerDirectInput.readObject(DataContainer.java:643)
    at org.jboss.serial.io.JBossObjectInputStream.readObjectOverride(JBossObjectInputStream.java:163)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:364)
    at SerializationTest.getObjectFromByteArray(SerializationTest.java:44)
    at SerializationTest.main(SerializationTest.java:15)
Caused by: java.lang.InstantiationException: MyObj
    at java.lang.Class.newInstance(Class.java:359)
    at org.jboss.serial.classmetamodel.ClassMetaData.newInstance(ClassMetaData.java:334)
    ... 8 more

      

Does anyone know what's going on here and how can I get around this?

Or, indeed, if JBossSerialization is not appropriate for this, then what?

Edit:

As @Dima points out, SerializationException

caused by the lack of a public default constructor for the class MyObj

. However, adding a default constructor to is MyObj

not an option as I would like to serialize arbitrary objects, including those that do not have a default constructor.

+3


source to share


1 answer


Well, it's actually impossible to do what you want in a way that is safe and versatile.

You can watch Kryo as someone suggested in the comments. It has a way to create objects without calling the constructor, but it is disabled by default and there is a good reason for that.

Consider this for example:

public class CanonicalObject {
    public static HashMap<String,CannicalObject> canons = new HahMap<~>();
    public String name;
    private CanonicalObject(String name) { 
        this.name = name;            
        canons.put(name, this);
    }
    public static synchronized CanonicalObject getCanonicalInstance(String name) {            
        CanonicalObject co = canon.get(name);
        return co == null ? new CanonicalObject(name) : co;
    }
}

      



(This is a "semi-real life" example that has real uses for this pattern. I know about "memory leaks", there are ways to avoid this in real applications, but they are irrelevant to this example, so I just ignore this problem for the sake of simplicity).

If you serialize an instance of this object when you deserialize it on the other end, the entire "canonicalization" part will be skipped, which can cause subtle problems in the application that are really hard to diagnose, such as comparisons like if(canon1 != canon2) fireMissile()

which leads to "friendly fire" and possibly WorldWar III.

Note that the problem here is broader than just a constructor not called by deserialization: the call canon.put

could well be placed in getCanonicalInstance()

instead of a constructor, and that would present a problem even if the constructor was called.

This is an illustration of why, in a policy, you should not serialize objects that are not intended to be serialized. Sometimes IT can work, but when it doesn't, it leads to situations that are really hard to detect and tend to be even more difficult to fix.

+2


source







All Articles