Question

I have read a little bit about 3rd party serialization methods such as JSON, but was wondering if there is any other way to serialize objects such as an area that do not implement serializable. In other word would JSON be the best way to serialize such an object?

EDIT : Throwing A NotSerializable Exception

public class Test {



public static void main(String[] args) throws Exception {
    Pojo pojo = new Pojo(new Area()); // The original object, NOT SERIALIZABLE !
    byte[] pojoBytes = Serializer.serialize(pojo); // Serialize
    pojo = (Pojo) Serializer.deserialize(pojoBytes); // Deserialize
    System.out.println(pojo); // Good as new !
}

} 

public class Pojo implements Serializable {
private final Area msg;
public Pojo(Area msg) {
    this.msg = msg;
}
public Area getMsg() {
    return msg;
}
public String toString() {
    return "Pojo says : " + msg;
}
}

public class Serializer {

public static byte[] serialize(Object o) throws Exception {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
FileOutputStream fileOut = new FileOutputStream("Test.ser");
ObjectOutputStream oos = new SurrogateObjectOutputStream(fileOut); // Magically handle Pojos !
oos.writeObject(o);
oos.flush();
oos.close();
return baos.toByteArray();
}

public static Object deserialize(byte[] bytes) throws IOException, ClassNotFoundException {
    ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
    FileInputStream fileIn = new FileInputStream("Test.ser");
    ObjectInputStream ois = new ObjectInputStream(fileIn);
    Object o = ois.readObject();
    bais.close();
    return o;
}

}

public class SurrogateObjectOutputStream extends ObjectOutputStream {

public SurrogateObjectOutputStream(OutputStream out) throws IOException {
    super(out);
    enableReplaceObject(true);
}

protected SurrogateObjectOutputStream() throws IOException, SecurityException {
    super();
    enableReplaceObject(true);
}

@Override
protected Object replaceObject(Object obj) throws IOException {
    if (obj instanceof Pojo) {
        return new PojoSurrogate((Pojo) obj);
    } else return super.replaceObject(obj);
}

}

public class PojoSurrogate implements Serializable {

private Area foo;

public PojoSurrogate(Pojo pojo) {
    this.foo = pojo.getMsg();
}   

private Object readResolve() throws ObjectStreamException {
    return new Pojo(foo);
}

}
Was it helpful?

Solution

It depends, if you want to use that Object in another program or another language for that matter, then yes JSON is the way to go (or XML).

But if you want to reuse that Object in another JAVA program then I guess it would be more convenient to look for a way to make possible non-serializable Objects serializable.

I haven't tested it yet, but I found a promising solution in this blog (which is in French, sorry). I'll try my best to summarize it:

what you have

say you have a class names Pojo and you want to serialize it although you don't know if it is serializable or not.

public final class Pojo {

    private final String msg;

    public Pojo(String msg) {
        this.msg = msg;
    }

    public String getMsg() {
        return msg;
    }

    public String toString() {
        return "Pojo says : " + msg;
    }
}

what you need

what you need is a new class that acts as a surrogate, which will take the member variables of the real Pojo and simply replace it.

public class PojoSurrogate implements Serializable {

    private String foo;

    public PojoSurrogate(Pojo pojo) {
        this.foo = pojo.getMsg();
    }   

    private Object readResolve() throws ObjectStreamException {
        return new Pojo(foo);
    } 
}

the last method ( readResolve() ) is the one that will in the end give you back your new Pojo later.

The other thing you need is your own surrogate version of the ObjectOutputStream:

public class SurrogateObjectOutputStream extends ObjectOutputStream {

    public SurrogateObjectOutputStream(OutputStream out) throws IOException {
        super(out);
        enableReplaceObject(true);
    }

    protected SurrogateObjectOutputStream() throws IOException, SecurityException {
        super();
        enableReplaceObject(true);
    }

    @Override
    protected Object replaceObject(Object obj) throws IOException {
        if (obj instanceof Pojo) {
            return new PojoSurrogate((Pojo) obj);
        } else return super.replaceObject(obj);
    } 
}

And again here the last method replaceObject() will do the magic and transform the Pojo into the serializable version PojoSurrogate to store all the information as bytes.

Serialize like this

ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new SurrogateObjectOutputStream(baos); 
oos.writeObject(o);
oos.flush();
oos.close();

byte[] serializedPojo = baos.toByteArray();  

Deserialize normally

ObjectInputStream bais = new ObjectInputStream(new ByteArrayInputStream( serializedPojo ));
Pojo myNewPojo = (Pojo) bais.readObject();
bais.close();

Sorry, long answer.. and I hope I haven't missed anything supercool from that blog where it is easier to create a more scalable solution.. hope this helps anyway!

[EDIT:]

I tried your code with an Area object and here is how I got some thing to work (although I am not sure if this is actually working with all Areas, so you might have to test if your areas still have the same characteristics after deserialization)

AreaSurrogate

public class AreaSurrogate implements Serializable {

    private final Rectangle bounds;

    public AreaSurrogate(Area area) {
        this.bounds = area.getBounds();
    }

    private Object readResolve() throws ObjectStreamException {
        return new Area(bounds);
    }
}    

SurrogateOutputStream

public class SurrogateOutputStream extends ObjectOutputStream {

    public SurrogateOutputStream(OutputStream out) throws IOException {
        super(out);
        enableReplaceObject(true);
    }

    protected SurrogateOutputStream() throws IOException, SecurityException {
        super();
        enableReplaceObject(true);
    }

    @Override
    protected Object replaceObject(Object obj) throws IOException {
        if (obj instanceof Area) {
            return new AreaSurrogate((Area) obj);
        } else {
            return super.replaceObject(obj);
        }
    }
}

Serializer

public class Serializer {

    public static byte[] serialize(Object o) throws Exception {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new SurrogateOutputStream(baos); // Magically handle Pojos !
        oos.writeObject(o);
        oos.flush();
        oos.close();
        return baos.toByteArray();
    }

    public static Object deserialize(byte[] bytes) throws IOException, ClassNotFoundException {
        ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
        ObjectInputStream ois = new ObjectInputStream(bais);
        Object o = ois.readObject();
        bais.close();
        return o;
    }
}

Main (to test)

public static void main(String[] args) throws Exception {
    Area area = new Area(new Rectangle(0, 0, 100, 100)); // The original object, NOT SERIALIZABLE !
    System.out.println(area.contains(new Rectangle(1, 1, 10, 10))); // Good as new !
    System.out.print("serializing...");
    byte[] pojoBytes = Serializer.serialize(area); // Serialize
    System.out.println("done");
    System.out.print("deserializing...");
    area = (Area) Serializer.deserialize(pojoBytes); // Deserialize
    System.out.println("done");
    System.out.println(area.contains(new Rectangle(1, 1, 10, 10))); // Good as new !
}

In the main() I create an Area from a Rectangle which starts at Coordinate (0,0) and is 100 wide and 100 high. Then I test if the Rectangle from (1,1) with 10 width and 10 height is inside the area (which it is, forcibly). After serializing and deserializing I test if the same Rectangle is still inside the new Area.

This might be insufficient, since the new Area Object is created from a Rectangle (see AreaSurrogate). so this might not work with other Area shapes..

expected output

true
serializing...done
deserializing...done
true
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top