Home | History | Annotate | Download | only in io
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package libcore.java.io;
     18 
     19 import java.io.ByteArrayInputStream;
     20 import java.io.ByteArrayOutputStream;
     21 import java.io.IOException;
     22 import java.io.ObjectInputStream;
     23 import java.io.ObjectOutputStream;
     24 import java.io.Serializable;
     25 import java.util.Arrays;
     26 import java.util.List;
     27 import junit.framework.TestCase;
     28 
     29 public final class ObjectOutputStreamTest extends TestCase {
     30     public void testLongString() throws Exception {
     31         // Most modified UTF-8 is limited to 64KiB, but serialized strings can have an 8-byte
     32         // length, so this should never throw java.io.UTFDataFormatException...
     33         StringBuilder sb = new StringBuilder();
     34         for (int i = 0; i < 64*1024 * 2; ++i) {
     35             sb.append('a');
     36         }
     37         String s = sb.toString();
     38         ObjectOutputStream os = new ObjectOutputStream(new ByteArrayOutputStream());
     39         os.writeObject(s);
     40     }
     41 
     42     public static class CallsCloseInWriteObjectMethod implements Serializable {
     43         private String message;
     44 
     45         public CallsCloseInWriteObjectMethod(String message) {
     46             this.message = message;
     47         }
     48 
     49         private void writeObject(ObjectOutputStream oos) throws IOException {
     50             oos.writeObject(message);
     51             oos.close();
     52         }
     53 
     54         private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
     55             message = (String) ois.readObject();
     56         }
     57 
     58         @Override
     59         public boolean equals(Object o) {
     60             if (this == o) {
     61                 return true;
     62             }
     63             if (o == null || getClass() != o.getClass()) {
     64                 return false;
     65             }
     66 
     67             CallsCloseInWriteObjectMethod that = (CallsCloseInWriteObjectMethod) o;
     68 
     69             return message.equals(that.message);
     70         }
     71 
     72         @Override
     73         public int hashCode() {
     74             return message.hashCode();
     75         }
     76     }
     77 
     78     // http://b/28159133
     79     public void testCloseInWriteObject() throws Exception {
     80         String hello = "Hello";
     81         CallsCloseInWriteObjectMethod object = new CallsCloseInWriteObjectMethod(hello);
     82         // This reproduces the problem in http://b/28159133 as follows:
     83         //   the list class gets handle N
     84         //   the object closes the ObjectOutputStream and clears the handle table
     85         //   the hello gets handle N
     86         //   the reuse of hello has a reference to handle N
     87         // When it is deserialized the list contains object, hello, Arrays.asList().getClass()
     88         // instead of object, hello, hello.
     89         List<Serializable> input = Arrays.asList(object, hello, hello);
     90         @SuppressWarnings("unchecked")
     91         List<CallsCloseInWriteObjectMethod> output = (List<CallsCloseInWriteObjectMethod>)
     92                 roundTrip(input);
     93 
     94         assertEquals(input, output);
     95     }
     96 
     97     private Serializable roundTrip(Object object)
     98             throws IOException, ClassNotFoundException {
     99         ByteArrayOutputStream baos = new ByteArrayOutputStream();
    100         try (ObjectOutputStream oos = new ObjectOutputStream(baos)) {
    101             oos.writeObject(object);
    102         }
    103 
    104         Serializable read;
    105         ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
    106         try (ObjectInputStream ois = new ObjectInputStream(bais)) {
    107             read = (Serializable) ois.readObject();
    108         }
    109         return read;
    110     }
    111 }
    112