Home | History | Annotate | Download | only in io
      1 /*
      2  *  Licensed to the Apache Software Foundation (ASF) under one or more
      3  *  contributor license agreements.  See the NOTICE file distributed with
      4  *  this work for additional information regarding copyright ownership.
      5  *  The ASF licenses this file to You under the Apache License, Version 2.0
      6  *  (the "License"); you may not use this file except in compliance with
      7  *  the License.  You may obtain a copy of the License at
      8  *
      9  *     http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  *  Unless required by applicable law or agreed to in writing, software
     12  *  distributed under the License is distributed on an "AS IS" BASIS,
     13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  *  See the License for the specific language governing permissions and
     15  *  limitations under the License.
     16  */
     17 
     18 package tests.api.java.io;
     19 
     20 import java.io.ByteArrayInputStream;
     21 import java.io.ByteArrayOutputStream;
     22 import java.io.EOFException;
     23 import java.io.IOException;
     24 import java.io.InputStream;
     25 import java.io.ObjectInputStream;
     26 import java.io.ObjectOutputStream;
     27 import java.io.ObjectStreamClass;
     28 import java.io.OutputStream;
     29 import java.io.Serializable;
     30 import java.io.StreamCorruptedException;
     31 import java.util.Arrays;
     32 import java.util.Hashtable;
     33 import java.util.Vector;
     34 import org.apache.harmony.testframework.serialization.SerializationTest;
     35 import org.apache.harmony.testframework.serialization.SerializationTest.SerializableAssert;
     36 import tests.support.Support_ASimpleInputStream;
     37 
     38 public class ObjectInputStreamTest extends junit.framework.TestCase implements
     39         Serializable {
     40 
     41     static final long serialVersionUID = 1L;
     42 
     43     ObjectInputStream ois;
     44 
     45     ObjectOutputStream oos;
     46 
     47     ByteArrayOutputStream bao;
     48 
     49     boolean readStreamHeaderCalled;
     50 
     51     private final String testString = "Lorem ipsum...";
     52 
     53     private final int testLength = testString.length();
     54 
     55     public void test_ConstructorLjava_io_InputStream_IOException() throws IOException {
     56         oos.writeObject(testString);
     57         oos.close();
     58 
     59         Support_ASimpleInputStream sis = new Support_ASimpleInputStream(bao.toByteArray());
     60         sis.throwExceptionOnNextUse = true;
     61         try {
     62             ois = new ObjectInputStream(sis);
     63             fail("Test 1: IOException expected.");
     64         } catch (IOException e) {
     65             // Expected.
     66         }
     67         sis.throwExceptionOnNextUse = false;
     68     }
     69 
     70     public void test_ClassDescriptor() throws IOException,
     71             ClassNotFoundException {
     72 
     73         ByteArrayOutputStream baos = new ByteArrayOutputStream();
     74         ObjectOutputStreamWithWriteDesc oos = new ObjectOutputStreamWithWriteDesc(
     75                 baos);
     76         oos.writeObject(String.class);
     77         oos.close();
     78         Class<?> cls = TestClassForSerialization.class;
     79         ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
     80         ObjectInputStreamWithReadDesc ois = new ObjectInputStreamWithReadDesc(
     81                 bais, cls);
     82         Object obj = ois.readObject();
     83         ois.close();
     84         assertEquals(cls, obj);
     85     }
     86 
     87     public void test_available() throws IOException {
     88         // Test for method int java.io.ObjectInputStream.available()
     89         oos.writeBytes(testString);
     90         oos.close();
     91 
     92         Support_ASimpleInputStream sis = new Support_ASimpleInputStream(bao.toByteArray());
     93         ois = new ObjectInputStream(sis);
     94         assertEquals("Test 1: Incorrect number of bytes;", testLength, ois.available());
     95         ois.close();
     96     }
     97 
     98     public void test_available_IOException() throws IOException {
     99         oos.writeObject(testString);
    100         oos.close();
    101 
    102         Support_ASimpleInputStream sis = new Support_ASimpleInputStream(bao.toByteArray());
    103         ois = new ObjectInputStream(sis);
    104         sis.throwExceptionOnNextUse = true;
    105         try {
    106             ois.available();
    107             fail("Test 1: IOException expected.");
    108         } catch (IOException e) {
    109             // Expected.
    110         }
    111         sis.throwExceptionOnNextUse = false;
    112         ois.close();
    113     }
    114 
    115     public void test_close() throws Exception {
    116         // Test for method void java.io.ObjectInputStream.close()
    117         oos.writeObject(testString);
    118         oos.close();
    119 
    120         Support_ASimpleInputStream sis = new Support_ASimpleInputStream(bao.toByteArray());
    121         ois = new ObjectInputStream(sis);
    122         sis.throwExceptionOnNextUse = true;
    123         try {
    124             ois.close();
    125             fail("Test 1: IOException expected.");
    126         } catch (IOException e) {
    127             // Expected.
    128         }
    129         sis.throwExceptionOnNextUse = false;
    130         ois.close();
    131     }
    132 
    133     public void test_enableResolveObjectB() throws IOException {
    134         // Start testing without a SecurityManager.
    135         BasicObjectInputStream bois = new BasicObjectInputStream();
    136         assertFalse("Test 1: Object resolving must be disabled by default.",
    137                 bois.enableResolveObject(true));
    138 
    139         assertTrue("Test 2: enableResolveObject did not return the previous value.",
    140                 bois.enableResolveObject(false));
    141     }
    142 
    143     public void test_read_IOException() throws IOException {
    144         oos.writeObject(testString);
    145         oos.close();
    146 
    147         Support_ASimpleInputStream sis = new Support_ASimpleInputStream(bao.toByteArray());
    148         ois = new ObjectInputStream(sis);
    149         sis.throwExceptionOnNextUse = true;
    150         try {
    151             ois.read();
    152             fail("Test 1: IOException expected.");
    153         } catch (IOException e) {
    154             // Expected.
    155         }
    156         sis.throwExceptionOnNextUse = false;
    157         ois.close();
    158     }
    159 
    160     public void test_read$BII() throws IOException {
    161         // Test for method int java.io.ObjectInputStream.read(byte [], int, int)
    162         byte[] buf = new byte[testLength];
    163         oos.writeBytes(testString);
    164         oos.close();
    165         ois = new ObjectInputStream(new ByteArrayInputStream(bao.toByteArray()));
    166         ois.read(buf, 0, testLength);
    167         ois.close();
    168         assertEquals("Read incorrect bytes", testString, new String(buf));
    169     }
    170 
    171     public void test_read$BII_Exception() throws IOException {
    172         byte[] buf = new byte[testLength];
    173         oos.writeObject(testString);
    174         oos.close();
    175 
    176         ois = new ObjectInputStream(new ByteArrayInputStream(bao.toByteArray()));
    177         try {
    178             ois.read(buf, 0, -1);
    179             fail("IndexOutOfBoundsException was not thrown.");
    180         } catch (IndexOutOfBoundsException e) {
    181             // Expected
    182         }
    183         try {
    184             ois.read(buf, -1,1);
    185             fail("IndexOutOfBoundsException was not thrown.");
    186         } catch (IndexOutOfBoundsException e) {
    187             // Expected
    188         }
    189         try {
    190             ois.read(buf, testLength, 1);
    191             fail("IndexOutOfBoundsException was not thrown.");
    192         } catch (IndexOutOfBoundsException e) {
    193             // Expected
    194         }
    195         ois.close();
    196 
    197 
    198         Support_ASimpleInputStream sis = new Support_ASimpleInputStream(bao.toByteArray());
    199         ois = new ObjectInputStream(sis);
    200         sis.throwExceptionOnNextUse = true;
    201         try {
    202             ois.read(buf, 0, testLength);
    203             fail("Test 1: IOException expected.");
    204         } catch (IOException e) {
    205             // Expected.
    206         }
    207         sis.throwExceptionOnNextUse = false;
    208         ois.close();
    209     }
    210 
    211     public void test_readFully$B() throws IOException {
    212         byte[] buf = new byte[testLength];
    213         oos.writeBytes(testString);
    214         oos.close();
    215         ois = new ObjectInputStream(new ByteArrayInputStream(bao.toByteArray()));
    216         ois.readFully(buf);
    217         assertEquals("Test 1: Incorrect bytes read;",
    218                 testString, new String(buf));
    219         ois.close();
    220 
    221         ois = new ObjectInputStream(new ByteArrayInputStream(bao.toByteArray()));
    222         ois.read();
    223         try {
    224             ois.readFully(buf);
    225             fail("Test 2: EOFException expected.");
    226         } catch (EOFException e) {
    227             // Expected.
    228         }
    229     }
    230 
    231     public void test_readFully$B_Exception() throws IOException {
    232         byte[] buf = new byte[testLength];
    233         oos.writeObject(testString);
    234         oos.close();
    235 
    236         Support_ASimpleInputStream sis = new Support_ASimpleInputStream(bao.toByteArray());
    237         ois = new ObjectInputStream(sis);
    238         sis.throwExceptionOnNextUse = true;
    239         try {
    240             ois.readFully(buf);
    241             fail("Test 1: IOException expected.");
    242         } catch (IOException e) {
    243             // Expected.
    244         }
    245         sis.throwExceptionOnNextUse = false;
    246         ois.close();
    247     }
    248 
    249     public void test_readFully$BII() throws IOException {
    250         // Test for method void java.io.ObjectInputStream.readFully(byte [],
    251         // int, int)
    252         byte[] buf = new byte[testLength];
    253         oos.writeBytes(testString);
    254         oos.close();
    255         ois = new ObjectInputStream(new ByteArrayInputStream(bao.toByteArray()));
    256         ois.readFully(buf, 0, testLength);
    257         assertEquals("Read incorrect bytes", testString, new String(buf));
    258         ois.close();
    259 
    260         ois = new ObjectInputStream(new ByteArrayInputStream(bao.toByteArray()));
    261         ois.read();
    262         try {
    263             ois.readFully(buf);
    264             fail("Test 2: EOFException expected.");
    265         } catch (EOFException e) {
    266             // Expected.
    267         }
    268     }
    269 
    270     public void test_readFully$BII_Exception() throws IOException {
    271         byte[] buf = new byte[testLength];
    272         oos.writeObject(testString);
    273         oos.close();
    274 
    275         ois = new ObjectInputStream(new ByteArrayInputStream(bao.toByteArray()));
    276         try {
    277             ois.readFully(buf, 0, -1);
    278             fail("IndexOutOfBoundsException was not thrown.");
    279         } catch (IndexOutOfBoundsException e) {
    280             // Expected
    281         }
    282         try {
    283             ois.readFully(buf, -1,1);
    284             fail("IndexOutOfBoundsException was not thrown.");
    285         } catch (IndexOutOfBoundsException e) {
    286             // Expected
    287         }
    288         try {
    289             ois.readFully(buf, testLength, 1);
    290             fail("IndexOutOfBoundsException was not thrown.");
    291         } catch (IndexOutOfBoundsException e) {
    292             // Expected
    293         }
    294         ois.close();
    295 
    296         Support_ASimpleInputStream sis = new Support_ASimpleInputStream(bao.toByteArray());
    297         ois = new ObjectInputStream(sis);
    298         sis.throwExceptionOnNextUse = true;
    299         try {
    300             ois.readFully(buf, 0, 1);
    301             fail("Test 1: IOException expected.");
    302         } catch (IOException e) {
    303             // Expected.
    304         }
    305         sis.throwExceptionOnNextUse = false;
    306         ois.close();
    307     }
    308 
    309     @SuppressWarnings("deprecation")
    310     public void test_readLine() throws IOException {
    311         String line;
    312         oos.writeBytes("Lorem\nipsum\rdolor sit amet...");
    313         oos.close();
    314 
    315         ois = new ObjectInputStream(new ByteArrayInputStream(bao.toByteArray()));
    316         line = ois.readLine();
    317         assertTrue("Test 1: Incorrect line written or read: " + line,
    318                 line.equals("Lorem"));
    319         line = ois.readLine();
    320         assertTrue("Test 2: Incorrect line written or read: " + line,
    321                 line.equals("ipsum"));
    322         line = ois.readLine();
    323         assertTrue("Test 3: Incorrect line written or read: " + line,
    324                 line.equals("dolor sit amet..."));
    325         ois.close();
    326     }
    327 
    328     public void test_readLine_IOException() throws IOException {
    329         oos.writeObject(testString);
    330         oos.close();
    331 
    332         Support_ASimpleInputStream sis = new Support_ASimpleInputStream(bao.toByteArray());
    333         ois = new ObjectInputStream(sis);
    334         sis.throwExceptionOnNextUse = true;
    335         try {
    336             ois.readLine();
    337             fail("Test 1: IOException expected.");
    338         } catch (IOException e) {
    339             // Expected.
    340         }
    341         sis.throwExceptionOnNextUse = false;
    342         ois.close();
    343     }
    344 
    345     private void fillStreamHeader(byte[] buffer) {
    346         short magic = java.io.ObjectStreamConstants.STREAM_MAGIC;
    347         short version = java.io.ObjectStreamConstants.STREAM_VERSION;
    348 
    349         if (buffer.length < 4) {
    350             throw new IllegalArgumentException("The buffer's minimal length must be 4.");
    351         }
    352 
    353         // Initialize the buffer with the correct header for object streams
    354         buffer[0] = (byte) (magic >> 8);
    355         buffer[1] = (byte) magic;
    356         buffer[2] = (byte) (version >> 8);
    357         buffer[3] = (byte) (version);
    358     }
    359 
    360     public void test_readObjectOverride() throws Exception {
    361         byte[] buffer = new byte[4];
    362 
    363         // Initialize the buffer with the correct header for object streams
    364         fillStreamHeader(buffer);
    365 
    366         // Test 1: Check that readObjectOverride() returns null if there
    367         // is no input stream.
    368         BasicObjectInputStream bois = new BasicObjectInputStream();
    369         assertNull("Test 1:", bois.readObjectOverride());
    370 
    371         // Test 2: Check that readObjectOverride() throws an IOException
    372         // if there is an input stream.
    373         bois = new BasicObjectInputStream(new ByteArrayInputStream(buffer));
    374         try {
    375             bois.readObjectOverride();
    376             fail("Test 2: IOException expected.");
    377         } catch (IOException e) {}
    378 
    379         bois.close();
    380     }
    381 
    382     public void test_readObjectMissingClasses() throws Exception {
    383         SerializationTest.verifySelf(new A1(), new SerializableAssert() {
    384             public void assertDeserialized(Serializable initial,
    385                     Serializable deserialized) {
    386                 assertEquals(5, ((A1) deserialized).b1.i);
    387             }
    388         });
    389     }
    390 
    391     public void test_readObjectCorrupt() {
    392         byte[] bytes = { 00, 00, 00, 0x64, 0x43, 0x48, (byte) 0xFD, 0x71, 00,
    393                 00, 0x0B, (byte) 0xB8, 0x4D, 0x65 };
    394         ByteArrayInputStream bin = new ByteArrayInputStream(bytes);
    395         boolean exception = false;
    396         try {
    397             ObjectInputStream in = new ObjectInputStream(bin);
    398             in.readObject();
    399             fail("Unexpected read of corrupted stream");
    400         } catch (StreamCorruptedException e) {
    401             exception = true;
    402         } catch (IOException e) {
    403             fail("Unexpected: " + e);
    404         } catch (ClassNotFoundException e) {
    405             fail("Unexpected: " + e);
    406         }
    407         assertTrue("Expected StreamCorruptedException", exception);
    408     }
    409 
    410     public void test_readStreamHeader() throws IOException {
    411         String testString = "Lorem ipsum";
    412         BasicObjectInputStream bois;
    413         short magic = java.io.ObjectStreamConstants.STREAM_MAGIC;
    414         short version = java.io.ObjectStreamConstants.STREAM_VERSION;
    415         byte[] buffer = new byte[20];
    416 
    417         // Initialize the buffer with the correct header for object streams
    418         fillStreamHeader(buffer);
    419         System.arraycopy(testString.getBytes(), 0, buffer, 4, testString.length());
    420 
    421         // Test 1: readStreamHeader should not throw a StreamCorruptedException.
    422         // It should get called by the ObjectInputStream constructor.
    423         try {
    424             readStreamHeaderCalled = false;
    425             bois = new BasicObjectInputStream(new ByteArrayInputStream(buffer));
    426             bois.close();
    427         } catch (StreamCorruptedException e) {
    428             fail("Test 1: Unexpected StreamCorruptedException.");
    429         }
    430         assertTrue("Test 1: readStreamHeader() has not been called.",
    431                     readStreamHeaderCalled);
    432 
    433         // Test 2: Make the stream magic number invalid and check that
    434         // readStreamHeader() throws an exception.
    435         buffer[0] = (byte)magic;
    436         buffer[1] = (byte)(magic >> 8);
    437         try {
    438             readStreamHeaderCalled = false;
    439             bois = new BasicObjectInputStream(new ByteArrayInputStream(buffer));
    440             fail("Test 2: StreamCorruptedException expected.");
    441             bois.close();
    442         } catch (StreamCorruptedException e) {
    443         }
    444         assertTrue("Test 2: readStreamHeader() has not been called.",
    445                     readStreamHeaderCalled);
    446 
    447         // Test 3: Make the stream version invalid and check that
    448         // readStreamHeader() throws an exception.
    449         buffer[0] = (byte)(magic >> 8);
    450         buffer[1] = (byte)magic;
    451         buffer[2] = (byte)(version);
    452         buffer[3] = (byte)(version >> 8);
    453         try {
    454             readStreamHeaderCalled = false;
    455             bois = new BasicObjectInputStream(new ByteArrayInputStream(buffer));
    456             fail("Test 3: StreamCorruptedException expected.");
    457             bois.close();
    458         } catch (StreamCorruptedException e) {
    459         }
    460         assertTrue("Test 3: readStreamHeader() has not been called.",
    461                     readStreamHeaderCalled);
    462     }
    463 
    464     public void test_readUnsignedByte() throws IOException {
    465         oos.writeByte(-1);
    466         oos.close();
    467 
    468         ois = new ObjectInputStream(new ByteArrayInputStream(bao.toByteArray()));
    469         assertEquals("Test 1: Incorrect unsigned byte written or read.",
    470                 255, ois.readUnsignedByte());
    471 
    472         try {
    473             ois.readUnsignedByte();
    474             fail("Test 2: EOFException expected.");
    475         } catch (EOFException e) {
    476             // Expected.
    477         }
    478 
    479         ois.close();
    480         try {
    481             ois.readUnsignedByte();
    482             fail("Test 3: IOException expected.");
    483         } catch (IOException e) {
    484             // Expected.
    485         }
    486     }
    487 
    488     public void test_readUnsignedShort() throws IOException {
    489         // Test for method int java.io.ObjectInputStream.readUnsignedShort()
    490         oos.writeShort(-1);
    491         oos.close();
    492 
    493         ois = new ObjectInputStream(new ByteArrayInputStream(bao.toByteArray()));
    494         assertEquals("Test 1: Incorrect unsigned short written or read.",
    495                 65535, ois.readUnsignedShort());
    496 
    497         try {
    498             ois.readUnsignedShort();
    499             fail("Test 2: EOFException expected.");
    500         } catch (EOFException e) {
    501             // Expected.
    502         }
    503 
    504         ois.close();
    505         try {
    506             ois.readUnsignedShort();
    507             fail("Test 3: IOException expected.");
    508         } catch (IOException e) {
    509             // Expected.
    510         }
    511     }
    512 
    513     public void test_resolveProxyClass() throws IOException {
    514         BasicObjectInputStream bois;
    515         byte[] buffer = new byte[10];
    516 
    517         // Initialize the buffer with the header for object streams
    518         fillStreamHeader(buffer);
    519         bois = new BasicObjectInputStream(new ByteArrayInputStream(buffer));
    520 
    521         // Test 1: Check that a NullPointerException is thrown
    522         // if null is passed to the method.
    523         try {
    524             bois.resolveProxyClass(null);
    525             fail("Test 1: NullPointerException expected.");
    526         }
    527         catch (NullPointerException npe) {
    528         }
    529         catch (ClassNotFoundException cnfe) {
    530             fail("Test 1: Unexpected ClassNotFoundException.");
    531         }
    532 
    533         // Test 2: Check that visible interfaces are found.
    534         try {
    535             String[] interfaces = { "java.io.Closeable",
    536                                     "java.lang.Cloneable" };
    537             bois.resolveProxyClass(interfaces);
    538         }
    539         catch (ClassNotFoundException cnfe) {
    540             fail("Test 2: Unexpected ClassNotFoundException.");
    541         }
    542 
    543         // Test 3: Check that a ClassNotFoundException is thrown if the
    544         // array of interfaces is not valid.
    545         try {
    546             String[] interfaces = { "java.io.Closeable",
    547                                     "java.io.Closeable" };
    548             bois.resolveProxyClass(interfaces);
    549             fail ("Test 3: ClassNotFoundException expected.");
    550         }
    551         catch (ClassNotFoundException cnfe) {
    552         }
    553 
    554         bois.close();
    555     }
    556 
    557     public void test_skipBytesI_IOException() throws IOException {
    558         oos.writeObject(testString);
    559         oos.close();
    560 
    561         Support_ASimpleInputStream sis = new Support_ASimpleInputStream(bao.toByteArray());
    562         ois = new ObjectInputStream(sis);
    563         sis.throwExceptionOnNextUse = true;
    564         try {
    565             ois.skipBytes(5);
    566             fail("Test 1: IOException expected.");
    567         } catch (IOException e) {
    568             // Expected.
    569         }
    570         sis.throwExceptionOnNextUse = false;
    571         ois.close();
    572     }
    573 
    574     public static class A implements Serializable {
    575 
    576         private static final long serialVersionUID = 11L;
    577 
    578         public String name = "name";
    579     }
    580 
    581     public static class B extends A {}
    582 
    583     public static class C extends B {
    584 
    585         private static final long serialVersionUID = 33L;
    586     }
    587 
    588     public static class A1 implements Serializable {
    589 
    590         static final long serialVersionUID = 5942584913446079661L;
    591 
    592         B1 b1 = new B1();
    593 
    594         B1 b2 = b1;
    595 
    596         Vector v = new Vector();
    597     }
    598 
    599     public static class B1 implements Serializable {
    600 
    601         int i = 5;
    602 
    603         Hashtable h = new Hashtable();
    604     }
    605 
    606     class BasicObjectInputStream extends ObjectInputStream {
    607         public BasicObjectInputStream() throws IOException, SecurityException {
    608             super();
    609         }
    610 
    611         public BasicObjectInputStream(InputStream input) throws IOException {
    612             super(input);
    613         }
    614 
    615         public boolean enableResolveObject(boolean enable)
    616                 throws SecurityException {
    617             return super.enableResolveObject(enable);
    618         }
    619 
    620         public Object readObjectOverride() throws ClassNotFoundException, IOException {
    621             return super.readObjectOverride();
    622         }
    623 
    624         public void readStreamHeader() throws IOException {
    625             readStreamHeaderCalled = true;
    626             super.readStreamHeader();
    627         }
    628 
    629         public Class<?> resolveProxyClass(String[] interfaceNames)
    630                 throws IOException, ClassNotFoundException {
    631             return super.resolveProxyClass(interfaceNames);
    632         }
    633     }
    634 
    635     //Regression Test for JIRA-2249
    636     public static class ObjectOutputStreamWithWriteDesc extends
    637             ObjectOutputStream {
    638         public ObjectOutputStreamWithWriteDesc(OutputStream os)
    639                 throws IOException {
    640             super(os);
    641         }
    642 
    643         public void writeClassDescriptor(ObjectStreamClass desc)
    644                 throws IOException {
    645         }
    646     }
    647 
    648     public static class ObjectInputStreamWithReadDesc extends
    649             ObjectInputStream {
    650         private Class returnClass;
    651 
    652         public ObjectInputStreamWithReadDesc(InputStream is, Class returnClass)
    653                 throws IOException {
    654             super(is);
    655             this.returnClass = returnClass;
    656         }
    657 
    658         public ObjectStreamClass readClassDescriptor() throws IOException,
    659                 ClassNotFoundException {
    660             return ObjectStreamClass.lookup(returnClass);
    661 
    662         }
    663     }
    664 
    665     static class TestClassForSerialization implements Serializable {
    666         private static final long serialVersionUID = 1L;
    667     }
    668 
    669     protected void setUp() throws Exception {
    670         super.setUp();
    671         oos = new ObjectOutputStream(bao = new ByteArrayOutputStream());
    672     }
    673 }
    674 
    675 class Test implements Serializable {
    676     private static final long serialVersionUID = 1L;
    677 
    678     Class<?> classes[] = new Class[] { byte.class, short.class, int.class,
    679             long.class, boolean.class, char.class, float.class, double.class };
    680 
    681     public boolean equals(Object o) {
    682         if (!(o instanceof Test)) {
    683             return false;
    684         }
    685         return Arrays.equals(classes, ((Test) o).classes);
    686     }
    687 }
    688