001package intermediate;
002
003import com.sandwich.koan.Koan;
004
005import java.io.*;
006import java.util.logging.Logger;
007
008import static com.sandwich.koan.constant.KoanConstants.__;
009import static com.sandwich.util.Assert.assertEquals;
010
011
012public class AboutSerialization {
013
014    @Koan
015    public void simpleSerialization() throws FileNotFoundException, IOException, ClassNotFoundException {
016        String s = "Hello world";
017        // serialize
018        File file = new File("SerializeFile");
019        file.deleteOnExit();
020        ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream(file));
021        os.writeObject(s);
022        os.close();
023
024        // deserialize
025        ObjectInputStream is = null;
026        try {
027            is = new ObjectInputStream(new FileInputStream("SerializeFile"));
028            String otherString = (String) is.readObject();
029            assertEquals(otherString, __);
030        } finally {
031            closeStream(is);
032        }
033    }
034
035    static class Starship implements Serializable {
036
037        // Although it is not enforced, you should define this constant
038        // to make sure you serialize/deserialize only compatible versions
039        // of your objects
040        private static final long serialVersionUID = 1L;
041        int maxWarpSpeed;
042    }
043
044    @Koan
045    public void customObjectSerialization() throws IOException, ClassNotFoundException {
046        Starship s = new Starship();
047        s.maxWarpSpeed = 9;
048        File file = new File("SerializeFile");
049        file.deleteOnExit();
050        ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream(file));
051        os.writeObject(s);
052        os.close();
053
054        ObjectInputStream is = null;
055        try {
056            is = new ObjectInputStream(new FileInputStream("SerializeFile"));
057            Starship onTheOtherSide = (Starship) is.readObject();
058            assertEquals(onTheOtherSide.maxWarpSpeed, __);
059        } finally {
060            closeStream(is);
061        }
062    }
063
064    static class Engine {
065        String type;
066
067        public Engine(String t) {
068            type = t;
069        }
070    }
071
072    @SuppressWarnings("serial")
073    static class Car implements Serializable {
074        // Transient means: Ignore field for serialization
075        transient Engine engine;
076
077        // Notice these methods are private and will be called by the JVM
078        // internally - as if they where defined by the Serializable interface
079        // but they aren't defined as part of the interface
080        private void writeObject(ObjectOutputStream os) throws IOException {
081            os.defaultWriteObject();
082            os.writeObject(engine.type);
083        }
084
085        private void readObject(ObjectInputStream is) throws IOException, ClassNotFoundException {
086            is.defaultReadObject();
087            engine = new Engine((String) is.readObject());
088        }
089    }
090
091    @Koan
092    public void customObjectSerializationWithTransientFields() throws FileNotFoundException, IOException, ClassNotFoundException {
093        // Note that this kind of access of fields is not good OO practice.
094        // But let's focus on serialization here :)
095        Car car = new Car();
096        car.engine = new Engine("diesel");
097        File file = new File("SerializeFile");
098        file.deleteOnExit();
099        ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream(file));
100        os.writeObject(car);
101        os.close();
102
103        ObjectInputStream is = null;
104        try {
105            is = new ObjectInputStream(new FileInputStream("SerializeFile"));
106            Car deserializedCar = (Car) is.readObject();
107            assertEquals(deserializedCar.engine.type, __);
108        } finally {
109            closeStream(is);
110        }
111    }
112
113    @SuppressWarnings("serial")
114    class Boat implements Serializable {
115        Engine engine;
116    }
117
118    @Koan
119    public void customSerializationWithUnserializableFields() throws FileNotFoundException, IOException {
120        Boat boat = new Boat();
121        boat.engine = new Engine("diesel");
122        File file = new File("SerializeFile");
123        file.deleteOnExit();
124        ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream(file));
125        String marker = "Start ";
126        try {
127            os.writeObject(boat);
128        } catch (NotSerializableException e) {
129            marker += "Exception";
130        }
131        os.close();
132        assertEquals(marker, __);
133    }
134
135    @SuppressWarnings("serial")
136    static class Animal implements Serializable {
137        String name;
138
139        public Animal(String s) {
140            name = s;
141        }
142    }
143
144    @SuppressWarnings("serial")
145    static class Dog extends Animal {
146        public Dog(String s) {
147            super(s);
148        }
149    }
150
151    @Koan
152    public void serializeWithInheritance() throws IOException, ClassNotFoundException {
153        Dog d = new Dog("snoopy");
154        File file = new File("SerializeFile");
155        file.deleteOnExit();
156        ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream(file));
157        os.writeObject(d);
158        os.close();
159
160        ObjectInputStream is = null;
161        try {
162            is = new ObjectInputStream(new FileInputStream("SerializeFile"));
163            Dog otherDog = (Dog) is.readObject();
164            assertEquals(otherDog.name, __);
165        } finally {
166            closeStream(is);
167        }
168    }
169
170    static class Plane {
171        String name;
172
173        public Plane(String s) {
174            name = s;
175        }
176
177        public Plane() {
178        }
179
180    }
181
182    @SuppressWarnings("serial")
183    static class MilitaryPlane extends Plane implements Serializable {
184        public MilitaryPlane(String s) {
185            super(s);
186        }
187    }
188
189    @Koan
190    public void serializeWithInheritanceWhenParentNotSerializable() throws FileNotFoundException, IOException, ClassNotFoundException {
191        MilitaryPlane p = new MilitaryPlane("F22");
192
193        ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("SerializeFile"));
194        os.writeObject(p);
195        os.close();
196
197        ObjectInputStream is = null;
198        try {
199            is = new ObjectInputStream(new FileInputStream("SerializeFile"));
200            MilitaryPlane otherPlane = (MilitaryPlane) is.readObject();
201            // Does this surprise you?
202            assertEquals(otherPlane.name, __);
203
204            // Think about how serialization creates objects...
205            // It does not use constructors! But if a parent object is not serializable
206            // it actually uses constructors and if the fields are not in a serializable class...
207            // unexpected things - like this - may happen
208        } finally {
209            closeStream(is);
210        }
211    }
212
213    private void closeStream(ObjectInputStream ois) {
214        if (ois != null) {
215            try {
216                ois.close();
217            } catch (IOException x) {
218                Logger.getAnonymousLogger().severe("Unable to close reader.");
219            }
220        }
221    }
222
223}
224