package intermediate; import com.sandwich.koan.Koan; import java.io.*; import java.util.logging.Logger; import static com.sandwich.koan.constant.KoanConstants.__; import static com.sandwich.util.Assert.assertEquals; public class AboutSerialization { @Koan public void simpleSerialization() throws FileNotFoundException, IOException, ClassNotFoundException { String s = "Hello world"; // serialize File file = new File("SerializeFile"); file.deleteOnExit(); ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream(file)); os.writeObject(s); os.close(); // deserialize ObjectInputStream is = null; try { is = new ObjectInputStream(new FileInputStream("SerializeFile")); String otherString = (String) is.readObject(); assertEquals(otherString, __); } finally { closeStream(is); } } static class Starship implements Serializable { // Although it is not enforced, you should define this constant // to make sure you serialize/deserialize only compatible versions // of your objects private static final long serialVersionUID = 1L; int maxWarpSpeed; } @Koan public void customObjectSerialization() throws IOException, ClassNotFoundException { Starship s = new Starship(); s.maxWarpSpeed = 9; File file = new File("SerializeFile"); file.deleteOnExit(); ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream(file)); os.writeObject(s); os.close(); ObjectInputStream is = null; try { is = new ObjectInputStream(new FileInputStream("SerializeFile")); Starship onTheOtherSide = (Starship) is.readObject(); assertEquals(onTheOtherSide.maxWarpSpeed, __); } finally { closeStream(is); } } static class Engine { String type; public Engine(String t) { type = t; } } @SuppressWarnings("serial") static class Car implements Serializable { // Transient means: Ignore field for serialization transient Engine engine; // Notice these methods are private and will be called by the JVM // internally - as if they where defined by the Serializable interface // but they aren't defined as part of the interface private void writeObject(ObjectOutputStream os) throws IOException { os.defaultWriteObject(); os.writeObject(engine.type); } private void readObject(ObjectInputStream is) throws IOException, ClassNotFoundException { is.defaultReadObject(); engine = new Engine((String) is.readObject()); } } @Koan public void customObjectSerializationWithTransientFields() throws FileNotFoundException, IOException, ClassNotFoundException { // Note that this kind of access of fields is not good OO practice. // But let's focus on serialization here :) Car car = new Car(); car.engine = new Engine("diesel"); File file = new File("SerializeFile"); file.deleteOnExit(); ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream(file)); os.writeObject(car); os.close(); ObjectInputStream is = null; try { is = new ObjectInputStream(new FileInputStream("SerializeFile")); Car deserializedCar = (Car) is.readObject(); assertEquals(deserializedCar.engine.type, __); } finally { closeStream(is); } } @SuppressWarnings("serial") class Boat implements Serializable { Engine engine; } @Koan public void customSerializationWithUnserializableFields() throws FileNotFoundException, IOException { Boat boat = new Boat(); boat.engine = new Engine("diesel"); File file = new File("SerializeFile"); file.deleteOnExit(); ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream(file)); String marker = "Start "; try { os.writeObject(boat); } catch (NotSerializableException e) { marker += "Exception"; } os.close(); assertEquals(marker, __); } @SuppressWarnings("serial") static class Animal implements Serializable { String name; public Animal(String s) { name = s; } } @SuppressWarnings("serial") static class Dog extends Animal { public Dog(String s) { super(s); } } @Koan public void serializeWithInheritance() throws IOException, ClassNotFoundException { Dog d = new Dog("snoopy"); File file = new File("SerializeFile"); file.deleteOnExit(); ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream(file)); os.writeObject(d); os.close(); ObjectInputStream is = null; try { is = new ObjectInputStream(new FileInputStream("SerializeFile")); Dog otherDog = (Dog) is.readObject(); assertEquals(otherDog.name, __); } finally { closeStream(is); } } static class Plane { String name; public Plane(String s) { name = s; } public Plane() { } } @SuppressWarnings("serial") static class MilitaryPlane extends Plane implements Serializable { public MilitaryPlane(String s) { super(s); } } @Koan public void serializeWithInheritanceWhenParentNotSerializable() throws FileNotFoundException, IOException, ClassNotFoundException { MilitaryPlane p = new MilitaryPlane("F22"); ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("SerializeFile")); os.writeObject(p); os.close(); ObjectInputStream is = null; try { is = new ObjectInputStream(new FileInputStream("SerializeFile")); MilitaryPlane otherPlane = (MilitaryPlane) is.readObject(); // Does this surprise you? assertEquals(otherPlane.name, __); // Think about how serialization creates objects... // It does not use constructors! But if a parent object is not serializable // it actually uses constructors and if the fields are not in a serializable class... // unexpected things - like this - may happen } finally { closeStream(is); } } private void closeStream(ObjectInputStream ois) { if (ois != null) { try { ois.close(); } catch (IOException x) { Logger.getAnonymousLogger().severe("Unable to close reader."); } } } }