Search code examples
javaarraysserializationcastinghashmap

How to retrieve object from key value database into Map, then convert back to object in Java


I am storing an object as a value in LevelDB. Both key and value must be in bytes for LevelDB.

I am receiving an object via a socket and casting it to MyObject:

MyObject myObject = (MyObject) (objectInput.readObject());

Then I am serialising my object when storing the value in LevelDB:

myLevelDb().put(bytes((publicKey)), Serializer.serialize(myObject));

The serializer code is as follows:

public static byte[] serialize(Object object) {

        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream out = null;
        try {
            out = new ObjectOutputStream(bos);
            out.writeObject(object);
            out.flush();
            byte[] yourBytes = bos.toByteArray();
            return yourBytes;
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                bos.close();
            } catch (IOException ex) {
                // ignore close exception
            }
        } return null;
    }

Then I am trying to iterate through the LevelDB and store each object into a Map. Here is where I am trying to deserialize the bytes back into MyObject and save them to Map:

private void iterateBytes() {
    DBIterator iterator = myLevelDb().iterator();
    while (iterator.hasNext()) {
        Map.Entry<byte[], byte[]> next = iterator.next();

        String keyString = new String(next.getKey());
        MyObject myObject = (MyObject) Serializer.deserialize(next.getValue());


        Map<String, MyObject> myMap = new HashMap<>();
        myMap().put(keyString, myObject);
    }
}

However, Java will not let me cast the deserialized bytes back to MyObject after it has been deserialized using the following code:

public static Object deserialize(byte[] bytes) {
        ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
        ObjectInput in = null;
        try {
            in = new ObjectInputStream(bis);
            Object o = in.readObject();

            return o;

        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            try {
                if (in != null) {
                    in.close();
                }
            } catch (IOException ex) {
                // ignore close exception
            }
        } return null;
    }

I don't understand why I cannot convert the object back from a byte[] when I have followed the exact same method of serializing and deserializing. MyObject implements Serializable and the SUID is correct, as it works on API calls between devices. I just cannot add it to a Map as the original object, nor will Java let me cast it.

This is the line where an error is thrown, no matter where I try to cast it back to myObject:

    MyObject myObject = (MyObject) Serializer.deserialize(next.getValue());

Error:

class java.lang.String cannot be cast to class myPackage.MyObject (java.lang.String is in module java.base of loader 'bootstrap';

Solution

  • This was solved by casting the generic Object object to MyObject (user defined class object) at serialization and also casting it at deserialization.

    Here is the code at serialization:

       public static byte[] serialize(MyObject myObject) {
    
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream out = null;
            try {
                out = new ObjectOutputStream(bos);
                out.writeObject(myObject);
                out.flush();
                byte[] yourBytes = bos.toByteArray();
                return yourBytes;
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    bos.close();
                } catch (IOException ex) {
                    // ignore close exception
                }
            } return null;
        }
    

    And here is the code for deserializaion.

     public static MyObject deserializeNodeClient(byte[] bytes) {
            ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
            ObjectInput in = null;
            try {
                in = new ObjectInputStream(bis);
                MyObject myObject = (MyObject) in.readObject();
    
                return myObject;
    
            } catch (IOException | ClassNotFoundException e) {
                e.printStackTrace();
            } finally {
                try {
                    if (in != null) {
                        in.close();
                    }
                } catch (IOException ex) {
                    // ignore close exception
                }
            } return null;
        }
    

    So although the original OP code works fine is some cases, the original object cannot be derived by using a generic Object object serialization, then casting the output.