Java像对象一样序列化对象

时间:2014-02-20 23:13:03

标签: java serialization area

我已经阅读了一些关于第三方序列化方法(如JSON)的内容,但是想知道是否有任何其他方法来序列化对象,例如不实现可序列化的区域。换句话说,JSON是序列化这样一个对象的最佳方式吗?

编辑:抛出NotSerializable异常

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);
}

}

1 个答案:

答案 0 :(得分:1)

这取决于,如果你想在另一个程序或其他语言中使用Object,那么 JSON是要走的路(或XML)。

但是如果你想在另一个JAVA程序中重用那个Object,那么我想找一种方法可以使 - 可序列化Objects更方便序列化的。

我还没有测试过,但我在this blog (which is in French, sorry)找到了一个很有希望的解决方案。我会尽力总结一下:

你有什么

假设您有一个类名Pojo,并且您想序列化它,尽管您不知道它是否可序列化。

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;
    }
}

您需要什么

你需要的是一个充当代理的新类,它将采用 real Pojo的成员变量并简单地替换它。

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);
    } 
}

最后一种方法(readResolve())最终会让您稍后返回新的Pojo

您需要的另一件事是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);
    } 
}

在这里,最后一个方法replaceObject()将完成魔术并将Pojo转换为可序列化版本PojoSurrogate,以将所有信息存储为字节。

像这样序列化

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

byte[] serializedPojo = baos.toByteArray();  

正常反序列化

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

很抱歉,很长的答案..我希望我没有错过任何来自该博客的超级冷却,因为它更容易创建一个更具可扩展性的解决方案..希望这无论如何都有帮助!

<强> [编辑:]

我尝试使用Area对象编写代码,这就是我如何使用某些东西(虽然我不确定这是否真的适用于所有Areas,所以你可能需要测试你的区域是否仍然存在反序列化后具有相同的特征)

<强> 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);
        }
    }
}

<强>串行

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;
    }
}

主要(测试)

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 !
}

main()我从Area创建Rectangle,从坐标(0,0)开始,宽100和高100。然后我测试从(1,1)宽度为10和高度为10的矩形是否在区域内(强制)。序列化和反序列化之后,我测试新的Area内是否还有相同的Rectangle。

这可能不够,因为新的Area对象是从Rectangle创建的(请参阅AreaSurrogate)。所以这可能不适用于其他区域形状..

预期输出

true
serializing...done
deserializing...done
true