1 /*
   2  * Copyright (c) 1999, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /* @test
  25  * @bug 4227189
  26  * @summary Ensure that class descriptor read, write hooks exist, are backwards
  27  *          compatible, and work as advertised.
  28  */
  29 
  30 import java.io.*;
  31 import java.util.*;
  32 
  33 class Foo implements Serializable {
  34     private static final long serialVersionUID = 1L;
  35     Short s = new Short((short) 1);
  36     Integer i = new Integer(2);
  37     Long l = new Long(3);
  38 
  39     public boolean equals(Object obj) {
  40         if (obj instanceof Foo) {
  41             Foo ofoo = (Foo) obj;
  42             return s.equals(ofoo.s) && i.equals(ofoo.i) && l.equals(ofoo.l);
  43         }
  44         return false;
  45     }
  46 }
  47 
  48 class CustomOutputStream extends ObjectOutputStream {
  49 
  50     boolean hookCalled = false;
  51 
  52     CustomOutputStream(OutputStream out) throws IOException {
  53         super(out);
  54         useProtocolVersion(PROTOCOL_VERSION_2);
  55     }
  56 
  57     protected void writeClassDescriptor(ObjectStreamClass desc)
  58         throws IOException
  59     {
  60         writeUTF(desc.getName());
  61         hookCalled = true;
  62     }
  63 }
  64 
  65 class CustomInputStream extends ObjectInputStream {
  66 
  67     boolean hookCalled = false;
  68 
  69     CustomInputStream(InputStream in) throws IOException {
  70         super(in);
  71     }
  72 
  73     protected ObjectStreamClass readClassDescriptor()
  74         throws IOException, ClassNotFoundException
  75     {
  76         hookCalled = true;
  77         return ObjectStreamClass.lookup(Class.forName(readUTF()));
  78     }
  79 }
  80 
  81 public class ClassDescHooks implements ObjectStreamConstants {
  82     public static void main(String[] args) throws Exception {
  83         ByteArrayOutputStream bout;
  84         ByteArrayInputStream bin;
  85         ObjectOutputStream oout;
  86         ObjectInputStream oin;
  87         FileInputStream fin;
  88         File foof;
  89         CustomOutputStream cout;
  90         CustomInputStream cin;
  91 
  92         // test for backwards compatibility
  93         bout = new ByteArrayOutputStream();
  94         foof = new File(System.getProperty("test.src", "."), "Foo.ser");
  95         fin = new FileInputStream(foof);
  96         try {
  97             while (fin.available() > 0)
  98                 bout.write(fin.read());
  99         } finally {
 100             fin.close();
 101         }
 102         byte[] buf1 = bout.toByteArray();
 103 
 104         bout = new ByteArrayOutputStream();
 105         oout = new ObjectOutputStream(bout);
 106         Foo foo = new Foo();
 107         oout.writeObject(foo);
 108         oout.flush();
 109         byte[] buf2 = bout.toByteArray();
 110 
 111         if (! Arrays.equals(buf1, buf2))
 112             throw new Error("Incompatible stream format (write)");
 113 
 114         Foo foocopy;
 115         fin = new FileInputStream(foof);
 116         try {
 117             oin = new ObjectInputStream(fin);
 118             foocopy = (Foo) oin.readObject();
 119             if (! foo.equals(foocopy))
 120                 throw new Error("Incompatible stream format (read)");
 121         } finally {
 122             fin.close();
 123         }
 124 
 125         // make sure write hook not called when old protocol in use
 126         bout = new ByteArrayOutputStream();
 127         cout = new CustomOutputStream(bout);
 128         cout.useProtocolVersion(PROTOCOL_VERSION_1);
 129         cout.writeObject(foo);
 130         if (cout.hookCalled)
 131             throw new Error("write descriptor hook should not be called");
 132 
 133         // write custom class descriptor representations
 134         bout = new ByteArrayOutputStream();
 135         cout = new CustomOutputStream(bout);
 136         cout.writeObject(foo);
 137         cout.flush();
 138         bin = new ByteArrayInputStream(bout.toByteArray());
 139         cin = new CustomInputStream(bin);
 140         foocopy = (Foo) cin.readObject();
 141         if (! cout.hookCalled)
 142             throw new Error("write descriptor hook never called");
 143         if (! cin.hookCalled)
 144             throw new Error("read descriptor hook never called");
 145         if (! foo.equals(foocopy))
 146             throw new Error("serialization failed when hooks active");
 147     }
 148 }