Java, сериализующий объекты как область

Я немного читал о сторонних методах сериализации, таких как 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);
}

}

person StoneAgeCoder    schedule 20.02.2014    source источник
comment
Вы пробовали это: stackoverflow.com/questions /2644172/   -  person Guy Bouallet    schedule 21.02.2014
comment
@Guy Bouallet Спасибо, вы все равно можете объяснить, почему это работает, вместо того, чтобы просто указывать Shape s = new Area();. Это потому, что форма сериализуема, и этот метод преобразует область в форму.   -  person StoneAgeCoder    schedule 21.02.2014


Ответы (1)


Это зависит от того, хотите ли вы использовать этот Object в другой программе или на другом языке, если на то пошло, тогда да JSON — это то, что вам нужно (или XML).

Но если вы хотите повторно использовать этот Object в другой программе JAVA, я думаю, было бы удобнее поискать способ сделать возможной не-сериализуемую Objects сериализуемую.

Я еще не тестировал его, но нашел многообещающее решение в этот блог (извините, на французском языке). Постараюсь резюмировать:

что у вас есть

скажем, у вас есть имена классов 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;
    }
}

что вам нужно

вам нужен новый класс, который действует как суррогат, который будет принимать переменные-члены реального 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, поэтому вам, возможно, придется проверить, имеют ли ваши области те же характеристики после десериализации)

Заместитель площади

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

Суррогатный выходной поток

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.

Этого может быть недостаточно, поскольку новый Объект Area создается из Rectangle (см. AreaSurrogate). так что это может не работать с другими формами Area..

ожидаемый результат

true
serializing...done
deserializing...done
true
person GameDroids    schedule 21.02.2014
comment
Как я могу реализовать это для конкретной области? Делает ли это все объекты в сериализуемом периоде java или есть некоторые исключения? - person StoneAgeCoder; 21.02.2014
comment
Насколько я знаю, это должно сделать все объекты сериализуемыми. Так что это должно работать и с Area объектами, хотя я не проверял это, извините. Но я не понимаю, почему любой объект не должен быть представлен как bytes. Хитрость заключается в том, чтобы сообщить Java, что эти байты могут быть реструктурированы как объект. Итак, самая важная часть заключается в том, что ваш суррогатный класс имеет метод readResolve() и implements Serializable. Все остальное кажется менее важным. Завтра я хочу попробовать это с Area Objects. Но, может быть, вы нашли ответ до тех пор :) - person GameDroids; 21.02.2014
comment
Спасибо огромное. Это позволяет мне контролировать свою программу, используя чистую Java. - person StoneAgeCoder; 21.02.2014
comment
Я получаю исключение NotSerializableException. Я отредактировал свой вопрос с помощью кода, но, похоже, все написано правильно. - person StoneAgeCoder; 21.02.2014
comment
Повторно протестировано с использованием французской версии, она работала со строкой. Протестировал его с Area и получил исключение NotSerializable. Репост версии Area. Я не знаю, что делать сейчас. Было бы разумно, если бы его можно было сериализовать, но, по-видимому, нет? - person StoneAgeCoder; 21.02.2014
comment
@StoneAgeCoder: взгляните на мою правку в ответе. Я попробовал ваш код, и по крайней мере часть из него заработала. - person GameDroids; 24.02.2014