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 org.apache.harmony.tests.java.io; 19 20 import java.io.Externalizable; 21 import java.io.IOException; 22 import java.io.ObjectInput; 23 import java.io.ObjectOutput; 24 import java.io.ObjectStreamClass; 25 import java.io.ObjectStreamField; 26 import java.io.Serializable; 27 import java.lang.reflect.Method; 28 import java.lang.reflect.Proxy; 29 import junit.framework.TestCase; 30 31 public class ObjectStreamClassTest extends TestCase { 32 33 static class DummyClass implements Serializable { 34 private static final long serialVersionUID = 999999999999999L; 35 36 long bam = 999L; 37 38 int ham = 9999; 39 40 public static long getUID() { 41 return serialVersionUID; 42 } 43 } 44 45 /** 46 * java.io.ObjectStreamClass#forClass() 47 */ 48 public void test_forClass() { 49 // Need to test during serialization to be sure an instance is 50 // returned 51 ObjectStreamClass osc = ObjectStreamClass.lookup(DummyClass.class); 52 assertEquals("forClass returned an object: " + osc.forClass(), 53 DummyClass.class, osc.forClass()); 54 } 55 56 /** 57 * java.io.ObjectStreamClass#getField(java.lang.String) 58 */ 59 public void test_getFieldLjava_lang_String() { 60 ObjectStreamClass osc = ObjectStreamClass.lookup(DummyClass.class); 61 assertEquals("getField did not return correct field", 'J', osc 62 .getField("bam").getTypeCode()); 63 assertNull("getField did not null for non-existent field", osc 64 .getField("wham")); 65 } 66 67 /** 68 * java.io.ObjectStreamClass#getFields() 69 */ 70 public void test_getFields() { 71 ObjectStreamClass osc = ObjectStreamClass.lookup(DummyClass.class); 72 ObjectStreamField[] osfArray = osc.getFields(); 73 assertTrue( 74 "Array of fields should be of length 2 but is instead of length: " 75 + osfArray.length, osfArray.length == 2); 76 } 77 78 /** 79 * java.io.ObjectStreamClass#getName() 80 */ 81 public void test_getName() { 82 ObjectStreamClass osc = ObjectStreamClass.lookup(DummyClass.class); 83 assertEquals( 84 "getName returned incorrect name: " + osc.getName(), 85 "org.apache.harmony.tests.java.io.ObjectStreamClassTest$DummyClass", 86 osc.getName()); 87 } 88 89 /** 90 * java.io.ObjectStreamClass#getSerialVersionUID() 91 */ 92 public void test_getSerialVersionUID() { 93 ObjectStreamClass osc = ObjectStreamClass.lookup(DummyClass.class); 94 assertTrue("getSerialversionUID returned incorrect uid: " 95 + osc.getSerialVersionUID() + " instead of " 96 + DummyClass.getUID(), osc.getSerialVersionUID() == DummyClass 97 .getUID()); 98 } 99 100 static class SyntheticTest implements Serializable { 101 private int i; 102 103 private class X implements Serializable { 104 public int get() { 105 return i; 106 } 107 } 108 109 public X foo() { 110 return new X(); 111 } 112 } 113 114 /** 115 * java.io.ObjectStreamClass#lookup(java.lang.Class) 116 */ 117 public void test_lookupLjava_lang_Class() { 118 ObjectStreamClass osc = ObjectStreamClass.lookup(DummyClass.class); 119 assertEquals( 120 "lookup returned wrong class: " + osc.getName(), 121 "org.apache.harmony.tests.java.io.ObjectStreamClassTest$DummyClass", 122 osc.getName()); 123 } 124 125 /** 126 * java.io.ObjectStreamClass#toString() 127 */ 128 public void test_toString() { 129 ObjectStreamClass osc = ObjectStreamClass.lookup(DummyClass.class); 130 String oscString = osc.toString(); 131 132 // The previous test was more specific than the spec so it was replaced 133 // with the test below 134 assertTrue("toString returned incorrect string: " + osc.toString(), 135 oscString.indexOf("serialVersionUID") >= 0 136 && oscString.indexOf("999999999999999L") >= 0); 137 } 138 139 public void testSerialization() { 140 ObjectStreamClass osc = ObjectStreamClass 141 .lookup(ObjectStreamClass.class); 142 assertEquals(0, osc.getFields().length); 143 } 144 145 public void test_specialTypes() { 146 Class<?> proxyClass = Proxy.getProxyClass(this.getClass() 147 .getClassLoader(), new Class[] { Runnable.class }); 148 149 ObjectStreamClass proxyStreamClass = ObjectStreamClass 150 .lookup(proxyClass); 151 152 assertEquals("Proxy classes should have zero serialVersionUID", 0, 153 proxyStreamClass.getSerialVersionUID()); 154 ObjectStreamField[] proxyFields = proxyStreamClass.getFields(); 155 assertEquals("Proxy classes should have no serialized fields", 0, 156 proxyFields.length); 157 158 ObjectStreamClass enumStreamClass = ObjectStreamClass 159 .lookup(Thread.State.class); 160 161 assertEquals("Enum classes should have zero serialVersionUID", 0, 162 enumStreamClass.getSerialVersionUID()); 163 ObjectStreamField[] enumFields = enumStreamClass.getFields(); 164 assertEquals("Enum classes should have no serialized fields", 0, 165 enumFields.length); 166 } 167 168 /** 169 * @since 1.6 170 */ 171 static class NonSerialzableClass { 172 private static final long serialVersionUID = 1l; 173 174 public static long getUID() { 175 return serialVersionUID; 176 } 177 } 178 179 /** 180 * @since 1.6 181 */ 182 static class ExternalizableClass implements Externalizable { 183 184 private static final long serialVersionUID = -4285635779249689129L; 185 186 public void readExternal(ObjectInput input) throws IOException, ClassNotFoundException { 187 throw new ClassNotFoundException(); 188 } 189 190 public void writeExternal(ObjectOutput output) throws IOException { 191 throw new IOException(); 192 } 193 194 } 195 196 /** 197 * java.io.ObjectStreamClass#lookupAny(java.lang.Class) 198 * @since 1.6 199 */ 200 public void test_lookupAnyLjava_lang_Class() { 201 // Test for method java.io.ObjectStreamClass 202 // java.io.ObjectStreamClass.lookupAny(java.lang.Class) 203 ObjectStreamClass osc = ObjectStreamClass.lookupAny(DummyClass.class); 204 assertEquals("lookup returned wrong class: " + osc.getName(), 205 "org.apache.harmony.tests.java.io.ObjectStreamClassTest$DummyClass", osc 206 .getName()); 207 208 osc = ObjectStreamClass.lookupAny(NonSerialzableClass.class); 209 assertEquals("lookup returned wrong class: " + osc.getName(), 210 "org.apache.harmony.tests.java.io.ObjectStreamClassTest$NonSerialzableClass", 211 osc.getName()); 212 213 osc = ObjectStreamClass.lookupAny(ExternalizableClass.class); 214 assertEquals("lookup returned wrong class: " + osc.getName(), 215 "org.apache.harmony.tests.java.io.ObjectStreamClassTest$ExternalizableClass", 216 osc.getName()); 217 218 osc = ObjectStreamClass.lookup(NonSerialzableClass.class); 219 assertNull(osc); 220 } 221 222 // http://b/28106822 223 public void testBug28106822() throws Exception { 224 Method getConstructorId = ObjectStreamClass.class.getDeclaredMethod( 225 "getConstructorId", Class.class); 226 getConstructorId.setAccessible(true); 227 228 assertEquals(1189998819991197253L, getConstructorId.invoke(null, Object.class)); 229 assertEquals(1189998819991197253L, getConstructorId.invoke(null, String.class)); 230 231 Method newInstance = ObjectStreamClass.class.getDeclaredMethod("newInstance", 232 Class.class, Long.TYPE); 233 newInstance.setAccessible(true); 234 235 Object obj = newInstance.invoke(null, String.class, 0 /* ignored */); 236 assertNotNull(obj); 237 assertTrue(obj instanceof String); 238 } 239 240 // Class without <clinit> method 241 public static class NoClinitParent { 242 } 243 // Class without <clinit> method 244 public static class NoClinitChildWithNoClinitParent extends NoClinitParent { 245 } 246 247 // Class with <clinit> method 248 public static class ClinitParent { 249 // This field will trigger creation of <clinit> method for this class 250 private static final String TAG = ClinitParent.class.getName(); 251 static { 252 253 } 254 } 255 // Class without <clinit> but with parent that has <clinit> method 256 public static class NoClinitChildWithClinitParent extends ClinitParent { 257 } 258 259 // http://b/29064453 260 public void testHasClinit() throws Exception { 261 Method hasStaticInitializer = 262 ObjectStreamClass.class.getDeclaredMethod("hasStaticInitializer", Class.class, 263 boolean.class); 264 hasStaticInitializer.setAccessible(true); 265 266 assertTrue((Boolean) 267 hasStaticInitializer.invoke(null, ClinitParent.class, 268 false /* checkSuperclass */)); 269 270 // RI will return correctly False in this case, but android has been returning true 271 // in this particular case. We're returning true to enable deserializing classes 272 // like NoClinitChildWithClinitParent without explicit serialVersionID field. 273 assertTrue((Boolean) 274 hasStaticInitializer.invoke(null, NoClinitChildWithClinitParent.class, 275 false /* checkSuperclass */)); 276 assertFalse((Boolean) 277 hasStaticInitializer.invoke(null, NoClinitParent.class, 278 false /* checkSuperclass */)); 279 assertFalse((Boolean) 280 hasStaticInitializer.invoke(null, NoClinitChildWithNoClinitParent.class, 281 false /* checkSuperclass */)); 282 283 284 assertTrue((Boolean) 285 hasStaticInitializer.invoke(null, ClinitParent.class, 286 true /* checkSuperclass */)); 287 assertFalse((Boolean) 288 hasStaticInitializer.invoke(null, NoClinitChildWithClinitParent.class, 289 true /* checkSuperclass */)); 290 assertFalse((Boolean) 291 hasStaticInitializer.invoke(null, NoClinitParent.class, 292 true /* checkSuperclass */)); 293 assertFalse((Boolean) 294 hasStaticInitializer.invoke(null, NoClinitChildWithNoClinitParent.class, 295 true /* checkSuperclass */)); 296 } 297 } 298