【问题标题】:Java Serializing Objects Like an AreaJava 像区域一样序列化对象
【发布时间】:2014-02-20 23:13:02
【问题描述】:

我已经阅读了一些关于 3rd 方序列化方法(例如 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);
}

}

【问题讨论】:

  • @Guy Bouallet 谢谢,无论如何你可以解释为什么这有效,而不是仅仅指定 Shape s = new Area();。是不是因为 shape 是可序列化的,并且这个方法将一个区域转换为一个 shape。

标签: java serialization area


【解决方案1】:

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

但是,如果您想在另一个 JAVA 程序中重用该 Object,那么我想寻找一种方法使 non-serializable Objects 可序列化成为可能会更方便。 p>

我还没有测试过,但我在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 的成员变量并简单地替换 em>它。

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,所以你可能需要测试你的区域是否仍然有反序列化后的相同特性)

区域代理

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() 中,我从Rectangle 创建一个Area,它从坐标(0,0) 开始,宽100,高100。然后我测试来自 (1,1) 的具有 10 宽度和 10 高度的矩形是否在该区域内(它是强制的)。序列化和反序列化后,我测试相同的 Rectangle 是否仍在新的 Area 内。

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

预期输出

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

【讨论】:

  • 我将如何专门针对某个区域实施此功能?这会使java中的所有对象都可序列化还是有一些例外?
  • AFAIK,它应该使所有对象可序列化。所以它也应该适用于Area Objects,虽然我还没有测试过,抱歉。但我不明白为什么任何对象都不应该表示为bytes。诀窍是告诉 Java 这些字节可以重组为一个对象。所以最重要的部分是你的代理类有readResolve()方法和implements Serializable。其他一切似乎都不那么重要了。我想明天用Area Objects 试试这个。但也许你在那之前找到了答案:)
  • 感谢负载。这使得我可以使用纯 java 保持对程序的控制。
  • 我收到 NotSerializableException 我用代码编辑了我的问题,但似乎都写得正确。
  • 使用与字符串一起使用的法语版本重新测试。用 Area 测试它并得到一个 NotSerializable 异常。重新发布区域版本。我不知道现在该怎么办。可以序列化但显然不是?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-08-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多