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 java.io; 19 20 import java.lang.ref.SoftReference; 21 import java.lang.reflect.Constructor; 22 import java.lang.reflect.Field; 23 import java.lang.reflect.Method; 24 import java.lang.reflect.Modifier; 25 import java.lang.reflect.Proxy; 26 import java.nio.ByteOrder; 27 import java.security.MessageDigest; 28 import java.security.NoSuchAlgorithmException; 29 import java.util.ArrayList; 30 import java.util.Arrays; 31 import java.util.Comparator; 32 import java.util.HashMap; 33 import java.util.List; 34 import java.util.WeakHashMap; 35 import libcore.io.Memory; 36 import libcore.util.EmptyArray; 37 38 /** 39 * Represents a descriptor for identifying a class during serialization and 40 * deserialization. Information contained in the descriptor includes the name 41 * and SUID of the class as well as field names and types. Information inherited 42 * from the superclasses is also taken into account. 43 * 44 * @see ObjectOutputStream 45 * @see ObjectInputStream 46 * @see java.lang.Class 47 */ 48 public class ObjectStreamClass implements Serializable { 49 50 // No need to compute the SUID for ObjectStreamClass, just use the value 51 // below 52 private static final long serialVersionUID = -6120832682080437368L; 53 54 // Name of the field that contains the SUID value (if present) 55 private static final String UID_FIELD_NAME = "serialVersionUID"; 56 57 static final long CONSTRUCTOR_IS_NOT_RESOLVED = -1; 58 59 private static final int CLASS_MODIFIERS_MASK = Modifier.PUBLIC | Modifier.FINAL | 60 Modifier.INTERFACE | Modifier.ABSTRACT; 61 62 private static final int FIELD_MODIFIERS_MASK = Modifier.PUBLIC | Modifier.PRIVATE | 63 Modifier.PROTECTED | Modifier.STATIC | Modifier.FINAL | Modifier.VOLATILE | 64 Modifier.TRANSIENT; 65 66 private static final int METHOD_MODIFIERS_MASK = Modifier.PUBLIC | Modifier.PRIVATE | 67 Modifier.PROTECTED | Modifier.STATIC | Modifier.FINAL | Modifier.SYNCHRONIZED | 68 Modifier.NATIVE | Modifier.ABSTRACT | Modifier.STRICT; 69 70 private static final Class<?>[] READ_PARAM_TYPES = new Class[] { ObjectInputStream.class }; 71 private static final Class<?>[] WRITE_PARAM_TYPES = new Class[] { ObjectOutputStream.class }; 72 73 /** 74 * Constant indicating that the class has no Serializable fields. 75 */ 76 public static final ObjectStreamField[] NO_FIELDS = new ObjectStreamField[0]; 77 78 /* 79 * used to fetch field serialPersistentFields and checking its type 80 */ 81 static final Class<?> ARRAY_OF_FIELDS; 82 83 static { 84 try { 85 ARRAY_OF_FIELDS = Class.forName("[Ljava.io.ObjectStreamField;"); 86 } catch (ClassNotFoundException e) { 87 // This should not happen 88 throw new AssertionError(e); 89 } 90 } 91 92 private static final String CLINIT_NAME = "<clinit>"; 93 94 private static final int CLINIT_MODIFIERS = Modifier.STATIC; 95 96 private static final String CLINIT_SIGNATURE = "()V"; 97 98 // Used to determine if an object is Serializable or Externalizable 99 private static final Class<Serializable> SERIALIZABLE = Serializable.class; 100 101 private static final Class<Externalizable> EXTERNALIZABLE = Externalizable.class; 102 103 // Used to test if the object is a String or a class. 104 static final Class<String> STRINGCLASS = String.class; 105 106 static final Class<?> CLASSCLASS = Class.class; 107 108 static final Class<ObjectStreamClass> OBJECTSTREAMCLASSCLASS = ObjectStreamClass.class; 109 110 private transient Method methodWriteReplace; 111 112 private transient Method methodReadResolve; 113 114 private transient Method methodWriteObject; 115 116 private transient Method methodReadObject; 117 118 private transient Method methodReadObjectNoData; 119 120 /** 121 * Indicates whether the class properties resolved 122 * 123 * @see #resolveProperties() 124 */ 125 private transient boolean arePropertiesResolved; 126 127 /** 128 * Cached class properties 129 * 130 * @see #resolveProperties() 131 * @see #isSerializable() 132 * @see #isExternalizable() 133 * @see #isProxy() 134 * @see #isEnum() 135 */ 136 private transient boolean isSerializable; 137 private transient boolean isExternalizable; 138 private transient boolean isProxy; 139 private transient boolean isEnum; 140 141 // ClassDesc // 142 143 // Name of the class this descriptor represents 144 private transient String className; 145 146 // Corresponding loaded class with the name above 147 private transient Class<?> resolvedClass; 148 149 private transient Class<?> resolvedConstructorClass; 150 private transient int resolvedConstructorMethodId; 151 152 // Serial version UID of the class the descriptor represents 153 private transient long svUID; 154 155 // ClassDescInfo // 156 157 // Any combination of SC_WRITE_METHOD, SC_SERIALIZABLE and SC_EXTERNALIZABLE 158 // (see ObjectStreamConstants) 159 private transient byte flags; 160 161 // Descriptor for the superclass of the class associated with this 162 // descriptor 163 private transient ObjectStreamClass superclass; 164 165 // Array of ObjectStreamField (see below) describing the fields of this 166 // class 167 private transient ObjectStreamField[] fields; 168 169 // Array of ObjectStreamField describing the serialized fields of this class 170 private transient ObjectStreamField[] loadFields; 171 172 // ObjectStreamField doesn't override hashCode or equals, so this is equivalent to an 173 // IdentityHashMap, which is fine for our purposes. 174 private transient HashMap<ObjectStreamField, Field> reflectionFields = 175 new HashMap<ObjectStreamField, Field>(); 176 177 // MethodID for deserialization constructor 178 private transient long constructor = CONSTRUCTOR_IS_NOT_RESOLVED; 179 180 void setConstructor(long newConstructor) { 181 constructor = newConstructor; 182 } 183 184 long getConstructor() { 185 return constructor; 186 } 187 188 Field getReflectionField(ObjectStreamField osf) { 189 synchronized (reflectionFields) { 190 Field field = reflectionFields.get(osf); 191 if (field != null) { 192 return field; 193 } 194 } 195 196 try { 197 Class<?> declaringClass = forClass(); 198 Field field = declaringClass.getDeclaredField(osf.getName()); 199 field.setAccessible(true); 200 synchronized (reflectionFields) { 201 reflectionFields.put(osf, field); 202 } 203 return reflectionFields.get(osf); 204 } catch (NoSuchFieldException ex) { 205 // The caller messed up. We'll return null and won't try to resolve this again. 206 return null; 207 } 208 } 209 210 /* 211 * If an ObjectStreamClass describes an Externalizable class, it (the 212 * descriptor) should not have field descriptors (ObjectStreamField) at all. 213 * The ObjectStreamClass that gets saved should simply have no field info. 214 * This is a footnote in page 1511 (class Serializable) of "The Java Class 215 * Libraries, Second Edition, Vol. I". 216 */ 217 218 /** 219 * Constructs a new instance of this class. 220 */ 221 ObjectStreamClass() { 222 } 223 224 /** 225 * Compute class descriptor for a given class <code>cl</code>. 226 * 227 * @param cl 228 * a java.langClass for which to compute the corresponding 229 * descriptor 230 * @return the computer class descriptor 231 */ 232 private static ObjectStreamClass createClassDesc(Class<?> cl) { 233 234 ObjectStreamClass result = new ObjectStreamClass(); 235 236 boolean isArray = cl.isArray(); 237 boolean serializable = isSerializable(cl); 238 boolean externalizable = isExternalizable(cl); 239 240 result.isSerializable = serializable; 241 result.isExternalizable = externalizable; 242 243 // Now we fill in the values 244 result.setName(cl.getName()); 245 result.setClass(cl); 246 Class<?> superclass = cl.getSuperclass(); 247 if (superclass != null) { 248 result.setSuperclass(lookup(superclass)); 249 } 250 251 Field[] declaredFields = null; 252 253 // Compute the SUID 254 if (serializable || externalizable) { 255 if (result.isEnum() || result.isProxy()) { 256 result.setSerialVersionUID(0L); 257 } else { 258 declaredFields = cl.getDeclaredFields(); 259 result.setSerialVersionUID(computeSerialVersionUID(cl, declaredFields)); 260 } 261 } 262 263 // Serializables need field descriptors 264 if (serializable && !isArray) { 265 if (declaredFields == null) { 266 declaredFields = cl.getDeclaredFields(); 267 } 268 result.buildFieldDescriptors(declaredFields); 269 } else { 270 // Externalizables or arrays do not need FieldDesc info 271 result.setFields(NO_FIELDS); 272 } 273 274 // Copy all fields to loadFields - they should be read by default in 275 // ObjectInputStream.defaultReadObject() method 276 ObjectStreamField[] fields = result.getFields(); 277 278 if (fields != null) { 279 ObjectStreamField[] loadFields = new ObjectStreamField[fields.length]; 280 281 for (int i = 0; i < fields.length; ++i) { 282 loadFields[i] = new ObjectStreamField(fields[i].getName(), 283 fields[i].getType(), fields[i].isUnshared()); 284 285 // resolve type string to init typeString field in 286 // ObjectStreamField 287 loadFields[i].getTypeString(); 288 } 289 result.setLoadFields(loadFields); 290 } 291 292 byte flags = 0; 293 if (externalizable) { 294 flags |= ObjectStreamConstants.SC_EXTERNALIZABLE; 295 flags |= ObjectStreamConstants.SC_BLOCK_DATA; // use protocol version 2 by default 296 } else if (serializable) { 297 flags |= ObjectStreamConstants.SC_SERIALIZABLE; 298 } 299 result.methodWriteReplace = findMethod(cl, "writeReplace"); 300 result.methodReadResolve = findMethod(cl, "readResolve"); 301 result.methodWriteObject = findPrivateMethod(cl, "writeObject", WRITE_PARAM_TYPES); 302 result.methodReadObject = findPrivateMethod(cl, "readObject", READ_PARAM_TYPES); 303 result.methodReadObjectNoData = findPrivateMethod(cl, "readObjectNoData", EmptyArray.CLASS); 304 if (result.hasMethodWriteObject()) { 305 flags |= ObjectStreamConstants.SC_WRITE_METHOD; 306 } 307 result.setFlags(flags); 308 309 return result; 310 } 311 312 /** 313 * Builds the collection of field descriptors for the receiver 314 * 315 * @param declaredFields 316 * collection of java.lang.reflect.Field for which to compute 317 * field descriptors 318 */ 319 void buildFieldDescriptors(Field[] declaredFields) { 320 // We could find the field ourselves in the collection, but calling 321 // reflect is easier. Optimize if needed. 322 final Field f = ObjectStreamClass.fieldSerialPersistentFields(this.forClass()); 323 // If we could not find the emulated fields, we'll have to compute 324 // dumpable fields from reflect fields 325 boolean useReflectFields = f == null; // Assume we will compute the 326 // fields to dump based on the 327 // reflect fields 328 329 ObjectStreamField[] _fields = null; 330 if (!useReflectFields) { 331 // The user declared a collection of emulated fields. Use them. 332 // We have to be able to fetch its value, even if it is private 333 f.setAccessible(true); 334 try { 335 // static field, pass null 336 _fields = (ObjectStreamField[]) f.get(null); 337 } catch (IllegalAccessException ex) { 338 throw new AssertionError(ex); 339 } 340 } else { 341 // Compute collection of dumpable fields based on reflect fields 342 List<ObjectStreamField> serializableFields = 343 new ArrayList<ObjectStreamField>(declaredFields.length); 344 // Filter, we are only interested in fields that are serializable 345 for (Field declaredField : declaredFields) { 346 int modifiers = declaredField.getModifiers(); 347 if (!Modifier.isStatic(modifiers) && !Modifier.isTransient(modifiers)) { 348 ObjectStreamField field = new ObjectStreamField(declaredField.getName(), 349 declaredField.getType()); 350 serializableFields.add(field); 351 } 352 } 353 354 if (serializableFields.size() == 0) { 355 _fields = NO_FIELDS; // If no serializable fields, share the 356 // special value so that users can test 357 } else { 358 _fields = serializableFields.toArray(new ObjectStreamField[serializableFields.size()]); 359 } 360 } 361 Arrays.sort(_fields); 362 // assign offsets 363 int primOffset = 0, objectOffset = 0; 364 for (int i = 0; i < _fields.length; i++) { 365 Class<?> type = _fields[i].getType(); 366 if (type.isPrimitive()) { 367 _fields[i].offset = primOffset; 368 primOffset += primitiveSize(type); 369 } else { 370 _fields[i].offset = objectOffset++; 371 } 372 } 373 fields = _fields; 374 } 375 376 /** 377 * Compute and return the Serial Version UID of the class {@code cl}. 378 * The value is computed based on the class name, superclass chain, field 379 * names, method names, modifiers, etc. 380 * 381 * @param cl 382 * a java.lang.Class for which to compute the SUID 383 * @param fields 384 * cl.getDeclaredFields(), pre-computed by the caller 385 * @return the value of SUID of this class 386 */ 387 private static long computeSerialVersionUID(Class<?> cl, Field[] fields) { 388 /* 389 * First we should try to fetch the static slot 'static final long 390 * serialVersionUID'. If it is defined, return it. If not defined, we 391 * really need to compute SUID using SHAOutputStream 392 */ 393 for (int i = 0; i < fields.length; i++) { 394 final Field field = fields[i]; 395 if (field.getType() == long.class) { 396 int modifiers = field.getModifiers(); 397 if (Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers)) { 398 if (UID_FIELD_NAME.equals(field.getName())) { 399 /* 400 * We need to be able to see it even if we have no 401 * visibility. That is why we set accessible first (new 402 * API in reflect 1.2) 403 */ 404 field.setAccessible(true); 405 try { 406 // Static field, parameter is ignored 407 return field.getLong(null); 408 } catch (IllegalAccessException iae) { 409 throw new RuntimeException("Error fetching SUID: " + iae); 410 } 411 } 412 } 413 } 414 } 415 416 MessageDigest digest; 417 try { 418 digest = MessageDigest.getInstance("SHA"); 419 } catch (NoSuchAlgorithmException e) { 420 throw new Error(e); 421 } 422 ByteArrayOutputStream sha = new ByteArrayOutputStream(); 423 try { 424 DataOutputStream output = new DataOutputStream(sha); 425 output.writeUTF(cl.getName()); 426 int classModifiers = CLASS_MODIFIERS_MASK & cl.getModifiers(); 427 /* 428 * Workaround for 1F9LOQO. Arrays are ABSTRACT in JDK, but that is 429 * not in the specification. Since we want to be compatible for 430 * X-loading, we have to pretend we have the same shape 431 */ 432 boolean isArray = cl.isArray(); 433 if (isArray) { 434 classModifiers |= Modifier.ABSTRACT; 435 } 436 // Required for JDK UID compatibility 437 if (cl.isInterface() && !Modifier.isPublic(classModifiers)) { 438 classModifiers &= ~Modifier.ABSTRACT; 439 } 440 output.writeInt(classModifiers); 441 442 /* 443 * In JDK1.2 arrays implement Cloneable and Serializable but not in 444 * JDK 1.1.7. So, JDK 1.2 "pretends" arrays have no interfaces when 445 * computing SHA-1 to be compatible. 446 */ 447 if (!isArray) { 448 // Interface information 449 Class<?>[] interfaces = cl.getInterfaces(); 450 if (interfaces.length > 1) { 451 // Only attempt to sort if really needed (saves object 452 // creation, etc) 453 Comparator<Class<?>> interfaceComparator = new Comparator<Class<?>>() { 454 public int compare(Class<?> itf1, Class<?> itf2) { 455 return itf1.getName().compareTo(itf2.getName()); 456 } 457 }; 458 Arrays.sort(interfaces, interfaceComparator); 459 } 460 461 // Dump them 462 for (int i = 0; i < interfaces.length; i++) { 463 output.writeUTF(interfaces[i].getName()); 464 } 465 } 466 467 // Field information 468 if (fields.length > 1) { 469 // Only attempt to sort if really needed (saves object creation, 470 // etc) 471 Comparator<Field> fieldComparator = new Comparator<Field>() { 472 public int compare(Field field1, Field field2) { 473 return field1.getName().compareTo(field2.getName()); 474 } 475 }; 476 Arrays.sort(fields, fieldComparator); 477 } 478 479 // Dump them 480 for (int i = 0; i < fields.length; i++) { 481 Field field = fields[i]; 482 int modifiers = field.getModifiers() & FIELD_MODIFIERS_MASK; 483 484 boolean skip = Modifier.isPrivate(modifiers) 485 && (Modifier.isTransient(modifiers) || Modifier 486 .isStatic(modifiers)); 487 if (!skip) { 488 // write name, modifier & "descriptor" of all but private 489 // static and private transient 490 output.writeUTF(field.getName()); 491 output.writeInt(modifiers); 492 output 493 .writeUTF(descriptorForFieldSignature(getFieldSignature(field))); 494 } 495 } 496 497 /* 498 * Normally constructors come before methods (because <init> < 499 * anyMethodName). However, <clinit> is an exception. Besides, 500 * reflect will not let us get to it. 501 */ 502 if (hasClinit(cl)) { 503 // write name, modifier & "descriptor" 504 output.writeUTF(CLINIT_NAME); 505 output.writeInt(CLINIT_MODIFIERS); 506 output.writeUTF(CLINIT_SIGNATURE); 507 } 508 509 // Constructor information 510 Constructor<?>[] constructors = cl.getDeclaredConstructors(); 511 if (constructors.length > 1) { 512 // Only attempt to sort if really needed (saves object creation, 513 // etc) 514 Comparator<Constructor<?>> constructorComparator = new Comparator<Constructor<?>>() { 515 public int compare(Constructor<?> ctr1, Constructor<?> ctr2) { 516 // All constructors have same name, so we sort based on 517 // signature 518 return (getConstructorSignature(ctr1) 519 .compareTo(getConstructorSignature(ctr2))); 520 } 521 }; 522 Arrays.sort(constructors, constructorComparator); 523 } 524 525 // Dump them 526 for (int i = 0; i < constructors.length; i++) { 527 Constructor<?> constructor = constructors[i]; 528 int modifiers = constructor.getModifiers() 529 & METHOD_MODIFIERS_MASK; 530 boolean isPrivate = Modifier.isPrivate(modifiers); 531 if (!isPrivate) { 532 /* 533 * write name, modifier & "descriptor" of all but private 534 * ones 535 * 536 * constructor.getName() returns the constructor name as 537 * typed, not the VM name 538 */ 539 output.writeUTF("<init>"); 540 output.writeInt(modifiers); 541 output.writeUTF(descriptorForSignature( 542 getConstructorSignature(constructor)).replace('/', 543 '.')); 544 } 545 } 546 547 // Method information 548 Method[] methods = cl.getDeclaredMethods(); 549 if (methods.length > 1) { 550 Comparator<Method> methodComparator = new Comparator<Method>() { 551 public int compare(Method m1, Method m2) { 552 int result = m1.getName().compareTo(m2.getName()); 553 if (result == 0) { 554 // same name, signature will tell which one comes 555 // first 556 return getMethodSignature(m1).compareTo( 557 getMethodSignature(m2)); 558 } 559 return result; 560 } 561 }; 562 Arrays.sort(methods, methodComparator); 563 } 564 565 // Dump them 566 for (int i = 0; i < methods.length; i++) { 567 Method method = methods[i]; 568 int modifiers = method.getModifiers() & METHOD_MODIFIERS_MASK; 569 boolean isPrivate = Modifier.isPrivate(modifiers); 570 if (!isPrivate) { 571 // write name, modifier & "descriptor" of all but private 572 // ones 573 output.writeUTF(method.getName()); 574 output.writeInt(modifiers); 575 output.writeUTF(descriptorForSignature( 576 getMethodSignature(method)).replace('/', '.')); 577 } 578 } 579 } catch (IOException e) { 580 throw new RuntimeException(e + " computing SHA-1/SUID"); 581 } 582 583 // now compute the UID based on the SHA 584 byte[] hash = digest.digest(sha.toByteArray()); 585 return Memory.peekLong(hash, 0, ByteOrder.LITTLE_ENDIAN); 586 } 587 588 /** 589 * Returns what the serialization specification calls "descriptor" given a 590 * field signature. 591 * 592 * @param signature 593 * a field signature 594 * @return containing the descriptor 595 */ 596 private static String descriptorForFieldSignature(String signature) { 597 return signature.replace('.', '/'); 598 } 599 600 /** 601 * Return what the serialization specification calls "descriptor" given a 602 * method/constructor signature. 603 * 604 * @param signature 605 * a method or constructor signature 606 * @return containing the descriptor 607 */ 608 private static String descriptorForSignature(String signature) { 609 return signature.substring(signature.indexOf("(")); 610 } 611 612 /** 613 * Return the java.lang.reflect.Field {@code serialPersistentFields} 614 * if class {@code cl} implements it. Return null otherwise. 615 * 616 * @param cl 617 * a java.lang.Class which to test 618 * @return {@code java.lang.reflect.Field} if the class has 619 * serialPersistentFields {@code null} if the class does not 620 * have serialPersistentFields 621 */ 622 static Field fieldSerialPersistentFields(Class<?> cl) { 623 try { 624 Field f = cl.getDeclaredField("serialPersistentFields"); 625 int modifiers = f.getModifiers(); 626 if (Modifier.isStatic(modifiers) && Modifier.isPrivate(modifiers) 627 && Modifier.isFinal(modifiers)) { 628 if (f.getType() == ARRAY_OF_FIELDS) { 629 return f; 630 } 631 } 632 } catch (NoSuchFieldException nsm) { 633 // Ignored 634 } 635 return null; 636 } 637 638 /** 639 * Returns the class (java.lang.Class) for this descriptor. 640 * 641 * @return the class in the local VM that this descriptor represents; 642 * {@code null} if there is no corresponding class. 643 */ 644 public Class<?> forClass() { 645 return resolvedClass; 646 } 647 648 /** 649 * Create and return a new instance of class 'instantiationClass' 650 * using JNI to call the constructor chosen by resolveConstructorClass. 651 * 652 * The returned instance may have uninitialized fields, including final fields. 653 */ 654 Object newInstance(Class<?> instantiationClass) throws InvalidClassException { 655 resolveConstructorClass(instantiationClass); 656 return newInstance(instantiationClass, resolvedConstructorMethodId); 657 } 658 private static native Object newInstance(Class<?> instantiationClass, int methodId); 659 660 private Class<?> resolveConstructorClass(Class<?> objectClass) throws InvalidClassException { 661 if (resolvedConstructorClass != null) { 662 return resolvedConstructorClass; 663 } 664 665 // The class of the instance may not be the same as the class of the 666 // constructor to run 667 // This is the constructor to run if Externalizable 668 Class<?> constructorClass = objectClass; 669 670 // WARNING - What if the object is serializable and externalizable ? 671 // Is that possible ? 672 boolean wasSerializable = (flags & ObjectStreamConstants.SC_SERIALIZABLE) != 0; 673 if (wasSerializable) { 674 // Now we must run the constructor of the class just above the 675 // one that implements Serializable so that slots that were not 676 // dumped can be initialized properly 677 while (constructorClass != null && ObjectStreamClass.isSerializable(constructorClass)) { 678 constructorClass = constructorClass.getSuperclass(); 679 } 680 } 681 682 // Fetch the empty constructor, or null if none. 683 Constructor<?> constructor = null; 684 if (constructorClass != null) { 685 try { 686 constructor = constructorClass.getDeclaredConstructor(EmptyArray.CLASS); 687 } catch (NoSuchMethodException ignored) { 688 } 689 } 690 691 // Has to have an empty constructor 692 if (constructor == null) { 693 String className = constructorClass != null ? constructorClass.getName() : null; 694 throw new InvalidClassException(className, "IllegalAccessException"); 695 } 696 697 int constructorModifiers = constructor.getModifiers(); 698 boolean isPublic = Modifier.isPublic(constructorModifiers); 699 boolean isProtected = Modifier.isProtected(constructorModifiers); 700 boolean isPrivate = Modifier.isPrivate(constructorModifiers); 701 702 // Now we must check if the empty constructor is visible to the 703 // instantiation class 704 boolean wasExternalizable = (flags & ObjectStreamConstants.SC_EXTERNALIZABLE) != 0; 705 if (isPrivate || (wasExternalizable && !isPublic)) { 706 throw new InvalidClassException(constructorClass.getName(), "IllegalAccessException"); 707 } 708 709 // We know we are testing from a subclass, so the only other case 710 // where the visibility is not allowed is when the constructor has 711 // default visibility and the instantiation class is in a different 712 // package than the constructor class 713 if (!isPublic && !isProtected) { 714 // Not public, not private and not protected...means default 715 // visibility. Check if same package 716 if (!inSamePackage(constructorClass, objectClass)) { 717 throw new InvalidClassException(constructorClass.getName(), "IllegalAccessException"); 718 } 719 } 720 721 resolvedConstructorClass = constructorClass; 722 resolvedConstructorMethodId = getConstructorId(resolvedConstructorClass); 723 return constructorClass; 724 } 725 private static native int getConstructorId(Class<?> c); 726 727 /** 728 * Checks if two classes belong to the same package. 729 * 730 * @param c1 731 * one of the classes to test. 732 * @param c2 733 * the other class to test. 734 * @return {@code true} if the two classes belong to the same package, 735 * {@code false} otherwise. 736 */ 737 private boolean inSamePackage(Class<?> c1, Class<?> c2) { 738 String nameC1 = c1.getName(); 739 String nameC2 = c2.getName(); 740 int indexDotC1 = nameC1.lastIndexOf('.'); 741 int indexDotC2 = nameC2.lastIndexOf('.'); 742 if (indexDotC1 != indexDotC2) { 743 return false; // cannot be in the same package if indices are not the same 744 } 745 if (indexDotC1 == -1) { 746 return true; // both of them are in default package 747 } 748 return nameC1.regionMatches(0, nameC2, 0, indexDotC1); 749 } 750 751 /** 752 * Return a String representing the signature for a Constructor {@code c}. 753 * 754 * @param c 755 * a java.lang.reflect.Constructor for which to compute the 756 * signature 757 * @return the constructor's signature 758 */ 759 static native String getConstructorSignature(Constructor<?> c); 760 761 /** 762 * Gets a field descriptor of the class represented by this class 763 * descriptor. 764 * 765 * @param name 766 * the name of the desired field. 767 * @return the field identified by {@code name} or {@code null} if there is 768 * no such field. 769 */ 770 public ObjectStreamField getField(String name) { 771 ObjectStreamField[] allFields = getFields(); 772 for (int i = 0; i < allFields.length; i++) { 773 ObjectStreamField f = allFields[i]; 774 if (f.getName().equals(name)) { 775 return f; 776 } 777 } 778 return null; 779 } 780 781 /** 782 * Returns the collection of field descriptors for the fields of the 783 * corresponding class 784 * 785 * @return the receiver's collection of declared fields for the class it 786 * represents 787 */ 788 ObjectStreamField[] fields() { 789 if (fields == null) { 790 Class<?> forCl = forClass(); 791 if (forCl != null && isSerializable() && !forCl.isArray()) { 792 buildFieldDescriptors(forCl.getDeclaredFields()); 793 } else { 794 // Externalizables or arrays do not need FieldDesc info 795 setFields(NO_FIELDS); 796 } 797 } 798 return fields; 799 } 800 801 /** 802 * Returns a collection of field descriptors for the serialized fields of 803 * the class represented by this class descriptor. 804 * 805 * @return an array of field descriptors or an array of length zero if there 806 * are no fields in this descriptor's class. 807 */ 808 public ObjectStreamField[] getFields() { 809 copyFieldAttributes(); 810 return loadFields == null ? fields().clone() : loadFields.clone(); 811 } 812 813 private transient volatile List<ObjectStreamClass> cachedHierarchy; 814 815 List<ObjectStreamClass> getHierarchy() { 816 List<ObjectStreamClass> result = cachedHierarchy; 817 if (result == null) { 818 cachedHierarchy = result = makeHierarchy(); 819 } 820 return result; 821 } 822 823 private List<ObjectStreamClass> makeHierarchy() { 824 ArrayList<ObjectStreamClass> result = new ArrayList<ObjectStreamClass>(); 825 for (ObjectStreamClass osc = this; osc != null; osc = osc.getSuperclass()) { 826 result.add(0, osc); 827 } 828 return result; 829 } 830 831 /** 832 * If a Class uses "serialPersistentFields" to define the serialized fields, 833 * this.loadFields cannot get the "unshared" information when deserializing 834 * fields using current implementation of ObjectInputStream. This method 835 * provides a way to copy the "unshared" attribute from this.fields. 836 * 837 */ 838 private void copyFieldAttributes() { 839 if ((loadFields == null) || fields == null) { 840 return; 841 } 842 843 for (int i = 0; i < loadFields.length; i++) { 844 ObjectStreamField loadField = loadFields[i]; 845 String name = loadField.getName(); 846 for (int j = 0; j < fields.length; j++) { 847 ObjectStreamField field = fields[j]; 848 if (name.equals(field.getName())) { 849 loadField.setUnshared(field.isUnshared()); 850 loadField.setOffset(field.getOffset()); 851 break; 852 } 853 } 854 } 855 } 856 857 /** 858 * Returns the collection of field descriptors for the input fields of the 859 * corresponding class 860 * 861 * @return the receiver's collection of input fields for the class it 862 * represents 863 */ 864 ObjectStreamField[] getLoadFields() { 865 return loadFields; 866 } 867 868 /** 869 * Return a String representing the signature for a field {@code f}. 870 * 871 * @param f 872 * a java.lang.reflect.Field for which to compute the signature 873 * @return the field's signature 874 */ 875 private static native String getFieldSignature(Field f); 876 877 /** 878 * Returns the flags for this descriptor, where possible combined values are 879 * 880 * ObjectStreamConstants.SC_WRITE_METHOD 881 * ObjectStreamConstants.SC_SERIALIZABLE 882 * ObjectStreamConstants.SC_EXTERNALIZABLE 883 * 884 * @return byte the receiver's flags for the class it represents 885 */ 886 byte getFlags() { 887 return flags; 888 } 889 890 /** 891 * Return a String representing the signature for a method {@code m}. 892 * 893 * @param m 894 * a java.lang.reflect.Method for which to compute the signature 895 * @return the method's signature 896 */ 897 static native String getMethodSignature(Method m); 898 899 /** 900 * Returns the name of the class represented by this descriptor. 901 * 902 * @return the fully qualified name of the class this descriptor represents. 903 */ 904 public String getName() { 905 return className; 906 } 907 908 /** 909 * Returns the Serial Version User ID of the class represented by this 910 * descriptor. 911 * 912 * @return the SUID for the class represented by this descriptor. 913 */ 914 public long getSerialVersionUID() { 915 return svUID; 916 } 917 918 /** 919 * Returns the descriptor (ObjectStreamClass) of the superclass of the class 920 * represented by the receiver. 921 * 922 * @return an ObjectStreamClass representing the superclass of the class 923 * represented by the receiver. 924 */ 925 ObjectStreamClass getSuperclass() { 926 return superclass; 927 } 928 929 /** 930 * Return true if the given class {@code cl} has the 931 * compiler-generated method {@code clinit}. Even though it is 932 * compiler-generated, it is used by the serialization code to compute SUID. 933 * This is unfortunate, since it may depend on compiler optimizations in 934 * some cases. 935 * 936 * @param cl 937 * a java.lang.Class which to test 938 * @return {@code true} if the class has <clinit> {@code false} 939 * if the class does not have <clinit> 940 */ 941 private static native boolean hasClinit(Class<?> cl); 942 943 /** 944 * Return true if instances of class {@code cl} are Externalizable, 945 * false otherwise. 946 * 947 * @param cl 948 * a java.lang.Class which to test 949 * @return {@code true} if instances of the class are Externalizable 950 * {@code false} if instances of the class are not 951 * Externalizable 952 * 953 * @see Object#hashCode 954 */ 955 static boolean isExternalizable(Class<?> cl) { 956 return EXTERNALIZABLE.isAssignableFrom(cl); 957 } 958 959 /** 960 * Return true if the type code 961 * <code>typecode<code> describes a primitive type 962 * 963 * @param typecode a char describing the typecode 964 * @return {@code true} if the typecode represents a primitive type 965 * {@code false} if the typecode represents an Object type (including arrays) 966 * 967 * @see Object#hashCode 968 */ 969 static boolean isPrimitiveType(char typecode) { 970 return !(typecode == '[' || typecode == 'L'); 971 } 972 973 /** 974 * Return true if instances of class {@code cl} are Serializable, 975 * false otherwise. 976 * 977 * @param cl 978 * a java.lang.Class which to test 979 * @return {@code true} if instances of the class are Serializable 980 * {@code false} if instances of the class are not 981 * Serializable 982 * 983 * @see Object#hashCode 984 */ 985 static boolean isSerializable(Class<?> cl) { 986 return SERIALIZABLE.isAssignableFrom(cl); 987 } 988 989 /** 990 * Resolves the class properties, if they weren't already 991 */ 992 private void resolveProperties() { 993 if (arePropertiesResolved) { 994 return; 995 } 996 997 Class<?> cl = forClass(); 998 isProxy = Proxy.isProxyClass(cl); 999 isEnum = Enum.class.isAssignableFrom(cl); 1000 isSerializable = isSerializable(cl); 1001 isExternalizable = isExternalizable(cl); 1002 1003 arePropertiesResolved = true; 1004 } 1005 1006 boolean isSerializable() { 1007 resolveProperties(); 1008 return isSerializable; 1009 } 1010 1011 boolean isExternalizable() { 1012 resolveProperties(); 1013 return isExternalizable; 1014 } 1015 1016 boolean isProxy() { 1017 resolveProperties(); 1018 return isProxy; 1019 } 1020 1021 boolean isEnum() { 1022 resolveProperties(); 1023 return isEnum; 1024 } 1025 1026 /** 1027 * Returns the descriptor for a serializable class. 1028 * Returns null if the class doesn't implement {@code Serializable} or {@code Externalizable}. 1029 * 1030 * @param cl 1031 * a java.lang.Class for which to obtain the corresponding 1032 * descriptor 1033 * @return the corresponding descriptor if the class is serializable or 1034 * externalizable; null otherwise. 1035 */ 1036 public static ObjectStreamClass lookup(Class<?> cl) { 1037 ObjectStreamClass osc = lookupStreamClass(cl); 1038 return (osc.isSerializable() || osc.isExternalizable()) ? osc : null; 1039 } 1040 1041 /** 1042 * Returns the descriptor for any class, whether or not the class 1043 * implements Serializable or Externalizable. 1044 * 1045 * @param cl 1046 * a java.lang.Class for which to obtain the corresponding 1047 * descriptor 1048 * @return the descriptor 1049 * @since 1.6 1050 */ 1051 public static ObjectStreamClass lookupAny(Class<?> cl) { 1052 return lookupStreamClass(cl); 1053 } 1054 1055 /** 1056 * Return the descriptor (ObjectStreamClass) corresponding to the class 1057 * {@code cl}. Returns an ObjectStreamClass even if instances of the 1058 * class cannot be serialized 1059 * 1060 * @param cl 1061 * a java.langClass for which to obtain the corresponding 1062 * descriptor 1063 * @return the corresponding descriptor 1064 */ 1065 static ObjectStreamClass lookupStreamClass(Class<?> cl) { 1066 WeakHashMap<Class<?>, ObjectStreamClass> tlc = getCache(); 1067 ObjectStreamClass cachedValue = tlc.get(cl); 1068 if (cachedValue == null) { 1069 cachedValue = createClassDesc(cl); 1070 tlc.put(cl, cachedValue); 1071 } 1072 return cachedValue; 1073 1074 } 1075 1076 /** 1077 * A ThreadLocal cache for lookupStreamClass, with the possibility of discarding the thread 1078 * local storage content when the heap is exhausted. 1079 */ 1080 private static SoftReference<ThreadLocal<WeakHashMap<Class<?>, ObjectStreamClass>>> storage = 1081 new SoftReference<ThreadLocal<WeakHashMap<Class<?>, ObjectStreamClass>>>(null); 1082 1083 private static WeakHashMap<Class<?>, ObjectStreamClass> getCache() { 1084 ThreadLocal<WeakHashMap<Class<?>, ObjectStreamClass>> tls = storage.get(); 1085 if (tls == null) { 1086 tls = new ThreadLocal<WeakHashMap<Class<?>, ObjectStreamClass>>() { 1087 public WeakHashMap<Class<?>, ObjectStreamClass> initialValue() { 1088 return new WeakHashMap<Class<?>, ObjectStreamClass>(); 1089 } 1090 }; 1091 storage = new SoftReference<ThreadLocal<WeakHashMap<Class<?>, ObjectStreamClass>>>(tls); 1092 } 1093 return tls.get(); 1094 } 1095 1096 /** 1097 * Return the java.lang.reflect.Method if class <code>cl</code> implements 1098 * <code>methodName</code> . Return null otherwise. 1099 * 1100 * @param cl 1101 * a java.lang.Class which to test 1102 * @return <code>java.lang.reflect.Method</code> if the class implements 1103 * writeReplace <code>null</code> if the class does not implement 1104 * writeReplace 1105 */ 1106 static Method findMethod(Class<?> cl, String methodName) { 1107 Class<?> search = cl; 1108 Method method = null; 1109 while (search != null) { 1110 try { 1111 method = search.getDeclaredMethod(methodName, (Class[]) null); 1112 if (search == cl 1113 || (method.getModifiers() & Modifier.PRIVATE) == 0) { 1114 method.setAccessible(true); 1115 return method; 1116 } 1117 } catch (NoSuchMethodException nsm) { 1118 } 1119 search = search.getSuperclass(); 1120 } 1121 return null; 1122 } 1123 1124 /** 1125 * Return the java.lang.reflect.Method if class <code>cl</code> implements 1126 * private <code>methodName</code> . Return null otherwise. 1127 * 1128 * @param cl 1129 * a java.lang.Class which to test 1130 * @return {@code java.lang.reflect.Method} if the class implements 1131 * writeReplace {@code null} if the class does not implement 1132 * writeReplace 1133 */ 1134 static Method findPrivateMethod(Class<?> cl, String methodName, 1135 Class<?>[] param) { 1136 try { 1137 Method method = cl.getDeclaredMethod(methodName, param); 1138 if (Modifier.isPrivate(method.getModifiers()) && method.getReturnType() == void.class) { 1139 method.setAccessible(true); 1140 return method; 1141 } 1142 } catch (NoSuchMethodException nsm) { 1143 // Ignored 1144 } 1145 return null; 1146 } 1147 1148 boolean hasMethodWriteReplace() { 1149 return (methodWriteReplace != null); 1150 } 1151 1152 Method getMethodWriteReplace() { 1153 return methodWriteReplace; 1154 } 1155 1156 boolean hasMethodReadResolve() { 1157 return (methodReadResolve != null); 1158 } 1159 1160 Method getMethodReadResolve() { 1161 return methodReadResolve; 1162 } 1163 1164 boolean hasMethodWriteObject() { 1165 return (methodWriteObject != null); 1166 } 1167 1168 Method getMethodWriteObject() { 1169 return methodWriteObject; 1170 } 1171 1172 boolean hasMethodReadObject() { 1173 return (methodReadObject != null); 1174 } 1175 1176 Method getMethodReadObject() { 1177 return methodReadObject; 1178 } 1179 1180 boolean hasMethodReadObjectNoData() { 1181 return (methodReadObjectNoData != null); 1182 } 1183 1184 Method getMethodReadObjectNoData() { 1185 return methodReadObjectNoData; 1186 } 1187 1188 void initPrivateFields(ObjectStreamClass desc) { 1189 methodWriteReplace = desc.methodWriteReplace; 1190 methodReadResolve = desc.methodReadResolve; 1191 methodWriteObject = desc.methodWriteObject; 1192 methodReadObject = desc.methodReadObject; 1193 methodReadObjectNoData = desc.methodReadObjectNoData; 1194 } 1195 1196 /** 1197 * Set the class (java.lang.Class) that the receiver represents 1198 * 1199 * @param c 1200 * aClass, the new class that the receiver describes 1201 */ 1202 void setClass(Class<?> c) { 1203 resolvedClass = c; 1204 } 1205 1206 /** 1207 * Set the collection of field descriptors for the fields of the 1208 * corresponding class 1209 * 1210 * @param f 1211 * ObjectStreamField[], the receiver's new collection of declared 1212 * fields for the class it represents 1213 */ 1214 void setFields(ObjectStreamField[] f) { 1215 fields = f; 1216 } 1217 1218 /** 1219 * Set the collection of field descriptors for the input fields of the 1220 * corresponding class 1221 * 1222 * @param f 1223 * ObjectStreamField[], the receiver's new collection of input 1224 * fields for the class it represents 1225 */ 1226 void setLoadFields(ObjectStreamField[] f) { 1227 loadFields = f; 1228 } 1229 1230 /** 1231 * Set the flags for this descriptor, where possible combined values are 1232 * 1233 * ObjectStreamConstants.SC_WRITE_METHOD 1234 * ObjectStreamConstants.SC_SERIALIZABLE 1235 * ObjectStreamConstants.SC_EXTERNALIZABLE 1236 * 1237 * @param b 1238 * byte, the receiver's new flags for the class it represents 1239 */ 1240 void setFlags(byte b) { 1241 flags = b; 1242 } 1243 1244 /** 1245 * Set the name of the class represented by the receiver 1246 * 1247 * @param newName 1248 * a String, the new fully qualified name of the class the 1249 * receiver represents 1250 */ 1251 void setName(String newName) { 1252 className = newName; 1253 } 1254 1255 /** 1256 * Set the Serial Version User ID of the class represented by the receiver 1257 * 1258 * @param l 1259 * a long, the new SUID for the class represented by the receiver 1260 */ 1261 void setSerialVersionUID(long l) { 1262 svUID = l; 1263 } 1264 1265 /** 1266 * Set the descriptor for the superclass of the class described by the 1267 * receiver 1268 * 1269 * @param c 1270 * an ObjectStreamClass, the new ObjectStreamClass for the 1271 * superclass of the class represented by the receiver 1272 */ 1273 void setSuperclass(ObjectStreamClass c) { 1274 superclass = c; 1275 } 1276 1277 private int primitiveSize(Class<?> type) { 1278 if (type == byte.class || type == boolean.class) { 1279 return 1; 1280 } 1281 if (type == short.class || type == char.class) { 1282 return 2; 1283 } 1284 if (type == int.class || type == float.class) { 1285 return 4; 1286 } 1287 if (type == long.class || type == double.class) { 1288 return 8; 1289 } 1290 throw new AssertionError(); 1291 } 1292 1293 /** 1294 * Returns a string containing a concise, human-readable description of this 1295 * descriptor. 1296 * 1297 * @return a printable representation of this descriptor. 1298 */ 1299 @Override 1300 public String toString() { 1301 return getName() + ": static final long serialVersionUID =" + getSerialVersionUID() + "L;"; 1302 } 1303 } 1304