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 long 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.isStatic(modifiers)); 486 if (!skip) { 487 // write name, modifier & "descriptor" of all but private 488 // static and private transient 489 output.writeUTF(field.getName()); 490 output.writeInt(modifiers); 491 output.writeUTF(descriptorForFieldSignature(getFieldSignature(field))); 492 } 493 } 494 495 /* 496 * Normally constructors come before methods (because <init> < 497 * anyMethodName). However, <clinit> is an exception. Besides, 498 * reflect will not let us get to it. 499 */ 500 if (hasClinit(cl)) { 501 // write name, modifier & "descriptor" 502 output.writeUTF(CLINIT_NAME); 503 output.writeInt(CLINIT_MODIFIERS); 504 output.writeUTF(CLINIT_SIGNATURE); 505 } 506 507 // Constructor information 508 Constructor<?>[] constructors = cl.getDeclaredConstructors(); 509 if (constructors.length > 1) { 510 // Only attempt to sort if really needed (saves object creation, 511 // etc) 512 Comparator<Constructor<?>> constructorComparator = new Comparator<Constructor<?>>() { 513 public int compare(Constructor<?> ctr1, Constructor<?> ctr2) { 514 // All constructors have same name, so we sort based on 515 // signature 516 return (getConstructorSignature(ctr1) 517 .compareTo(getConstructorSignature(ctr2))); 518 } 519 }; 520 Arrays.sort(constructors, constructorComparator); 521 } 522 523 // Dump them 524 for (int i = 0; i < constructors.length; i++) { 525 Constructor<?> constructor = constructors[i]; 526 int modifiers = constructor.getModifiers() 527 & METHOD_MODIFIERS_MASK; 528 boolean isPrivate = Modifier.isPrivate(modifiers); 529 if (!isPrivate) { 530 /* 531 * write name, modifier & "descriptor" of all but private 532 * ones 533 * 534 * constructor.getName() returns the constructor name as 535 * typed, not the VM name 536 */ 537 output.writeUTF("<init>"); 538 output.writeInt(modifiers); 539 output.writeUTF(descriptorForSignature( 540 getConstructorSignature(constructor)).replace('/', 541 '.')); 542 } 543 } 544 545 // Method information 546 Method[] methods = cl.getDeclaredMethods(); 547 if (methods.length > 1) { 548 Comparator<Method> methodComparator = new Comparator<Method>() { 549 public int compare(Method m1, Method m2) { 550 int result = m1.getName().compareTo(m2.getName()); 551 if (result == 0) { 552 // same name, signature will tell which one comes 553 // first 554 return getMethodSignature(m1).compareTo( 555 getMethodSignature(m2)); 556 } 557 return result; 558 } 559 }; 560 Arrays.sort(methods, methodComparator); 561 } 562 563 // Dump them 564 for (int i = 0; i < methods.length; i++) { 565 Method method = methods[i]; 566 int modifiers = method.getModifiers() & METHOD_MODIFIERS_MASK; 567 boolean isPrivate = Modifier.isPrivate(modifiers); 568 if (!isPrivate) { 569 // write name, modifier & "descriptor" of all but private 570 // ones 571 output.writeUTF(method.getName()); 572 output.writeInt(modifiers); 573 output.writeUTF(descriptorForSignature( 574 getMethodSignature(method)).replace('/', '.')); 575 } 576 } 577 } catch (IOException e) { 578 throw new RuntimeException(e + " computing SHA-1/SUID"); 579 } 580 581 // now compute the UID based on the SHA 582 byte[] hash = digest.digest(sha.toByteArray()); 583 return Memory.peekLong(hash, 0, ByteOrder.LITTLE_ENDIAN); 584 } 585 586 /** 587 * Returns what the serialization specification calls "descriptor" given a 588 * field signature. 589 * 590 * @param signature 591 * a field signature 592 * @return containing the descriptor 593 */ 594 private static String descriptorForFieldSignature(String signature) { 595 return signature.replace('.', '/'); 596 } 597 598 /** 599 * Return what the serialization specification calls "descriptor" given a 600 * method/constructor signature. 601 * 602 * @param signature 603 * a method or constructor signature 604 * @return containing the descriptor 605 */ 606 private static String descriptorForSignature(String signature) { 607 return signature.substring(signature.indexOf("(")); 608 } 609 610 /** 611 * Return the java.lang.reflect.Field {@code serialPersistentFields} 612 * if class {@code cl} implements it. Return null otherwise. 613 * 614 * @param cl 615 * a java.lang.Class which to test 616 * @return {@code java.lang.reflect.Field} if the class has 617 * serialPersistentFields {@code null} if the class does not 618 * have serialPersistentFields 619 */ 620 static Field fieldSerialPersistentFields(Class<?> cl) { 621 try { 622 Field f = cl.getDeclaredField("serialPersistentFields"); 623 int modifiers = f.getModifiers(); 624 if (Modifier.isStatic(modifiers) && Modifier.isPrivate(modifiers) 625 && Modifier.isFinal(modifiers)) { 626 if (f.getType() == ARRAY_OF_FIELDS) { 627 return f; 628 } 629 } 630 } catch (NoSuchFieldException nsm) { 631 // Ignored 632 } 633 return null; 634 } 635 636 /** 637 * Returns the class (java.lang.Class) for this descriptor. 638 * 639 * @return the class in the local VM that this descriptor represents; 640 * {@code null} if there is no corresponding class. 641 */ 642 public Class<?> forClass() { 643 return resolvedClass; 644 } 645 646 /** 647 * Create and return a new instance of class 'instantiationClass' 648 * using JNI to call the constructor chosen by resolveConstructorClass. 649 * 650 * The returned instance may have uninitialized fields, including final fields. 651 */ 652 Object newInstance(Class<?> instantiationClass) throws InvalidClassException { 653 resolveConstructorClass(instantiationClass); 654 return newInstance(instantiationClass, resolvedConstructorMethodId); 655 } 656 private static native Object newInstance(Class<?> instantiationClass, long methodId); 657 658 private Class<?> resolveConstructorClass(Class<?> objectClass) throws InvalidClassException { 659 if (resolvedConstructorClass != null) { 660 return resolvedConstructorClass; 661 } 662 663 // The class of the instance may not be the same as the class of the 664 // constructor to run 665 // This is the constructor to run if Externalizable 666 Class<?> constructorClass = objectClass; 667 668 // WARNING - What if the object is serializable and externalizable ? 669 // Is that possible ? 670 boolean wasSerializable = (flags & ObjectStreamConstants.SC_SERIALIZABLE) != 0; 671 if (wasSerializable) { 672 // Now we must run the constructor of the class just above the 673 // one that implements Serializable so that slots that were not 674 // dumped can be initialized properly 675 while (constructorClass != null && ObjectStreamClass.isSerializable(constructorClass)) { 676 constructorClass = constructorClass.getSuperclass(); 677 } 678 } 679 680 // Fetch the empty constructor, or null if none. 681 Constructor<?> constructor = null; 682 if (constructorClass != null) { 683 try { 684 constructor = constructorClass.getDeclaredConstructor(EmptyArray.CLASS); 685 } catch (NoSuchMethodException ignored) { 686 } 687 } 688 689 // Has to have an empty constructor 690 if (constructor == null) { 691 String className = constructorClass != null ? constructorClass.getName() : null; 692 throw new InvalidClassException(className, "IllegalAccessException"); 693 } 694 695 int constructorModifiers = constructor.getModifiers(); 696 boolean isPublic = Modifier.isPublic(constructorModifiers); 697 boolean isProtected = Modifier.isProtected(constructorModifiers); 698 boolean isPrivate = Modifier.isPrivate(constructorModifiers); 699 700 // Now we must check if the empty constructor is visible to the 701 // instantiation class 702 boolean wasExternalizable = (flags & ObjectStreamConstants.SC_EXTERNALIZABLE) != 0; 703 if (isPrivate || (wasExternalizable && !isPublic)) { 704 throw new InvalidClassException(constructorClass.getName(), "IllegalAccessException"); 705 } 706 707 // We know we are testing from a subclass, so the only other case 708 // where the visibility is not allowed is when the constructor has 709 // default visibility and the instantiation class is in a different 710 // package than the constructor class 711 if (!isPublic && !isProtected) { 712 // Not public, not private and not protected...means default 713 // visibility. Check if same package 714 if (!inSamePackage(constructorClass, objectClass)) { 715 throw new InvalidClassException(constructorClass.getName(), "IllegalAccessException"); 716 } 717 } 718 719 resolvedConstructorClass = constructorClass; 720 resolvedConstructorMethodId = getConstructorId(resolvedConstructorClass); 721 return constructorClass; 722 } 723 private static native long getConstructorId(Class<?> c); 724 725 /** 726 * Checks if two classes belong to the same package. 727 * 728 * @param c1 729 * one of the classes to test. 730 * @param c2 731 * the other class to test. 732 * @return {@code true} if the two classes belong to the same package, 733 * {@code false} otherwise. 734 */ 735 private boolean inSamePackage(Class<?> c1, Class<?> c2) { 736 String nameC1 = c1.getName(); 737 String nameC2 = c2.getName(); 738 int indexDotC1 = nameC1.lastIndexOf('.'); 739 int indexDotC2 = nameC2.lastIndexOf('.'); 740 if (indexDotC1 != indexDotC2) { 741 return false; // cannot be in the same package if indices are not the same 742 } 743 if (indexDotC1 == -1) { 744 return true; // both of them are in default package 745 } 746 return nameC1.regionMatches(0, nameC2, 0, indexDotC1); 747 } 748 749 /** 750 * Return a String representing the signature for a Constructor {@code c}. 751 * 752 * @param c 753 * a java.lang.reflect.Constructor for which to compute the 754 * signature 755 * @return the constructor's signature 756 */ 757 static native String getConstructorSignature(Constructor<?> c); 758 759 /** 760 * Gets a field descriptor of the class represented by this class 761 * descriptor. 762 * 763 * @param name 764 * the name of the desired field. 765 * @return the field identified by {@code name} or {@code null} if there is 766 * no such field. 767 */ 768 public ObjectStreamField getField(String name) { 769 ObjectStreamField[] allFields = getFields(); 770 for (int i = 0; i < allFields.length; i++) { 771 ObjectStreamField f = allFields[i]; 772 if (f.getName().equals(name)) { 773 return f; 774 } 775 } 776 return null; 777 } 778 779 /** 780 * Returns the collection of field descriptors for the fields of the 781 * corresponding class 782 * 783 * @return the receiver's collection of declared fields for the class it 784 * represents 785 */ 786 ObjectStreamField[] fields() { 787 if (fields == null) { 788 Class<?> forCl = forClass(); 789 if (forCl != null && isSerializable() && !forCl.isArray()) { 790 buildFieldDescriptors(forCl.getDeclaredFields()); 791 } else { 792 // Externalizables or arrays do not need FieldDesc info 793 setFields(NO_FIELDS); 794 } 795 } 796 return fields; 797 } 798 799 /** 800 * Returns a collection of field descriptors for the serialized fields of 801 * the class represented by this class descriptor. 802 * 803 * @return an array of field descriptors or an array of length zero if there 804 * are no fields in this descriptor's class. 805 */ 806 public ObjectStreamField[] getFields() { 807 copyFieldAttributes(); 808 return loadFields == null ? fields().clone() : loadFields.clone(); 809 } 810 811 private transient volatile List<ObjectStreamClass> cachedHierarchy; 812 813 List<ObjectStreamClass> getHierarchy() { 814 List<ObjectStreamClass> result = cachedHierarchy; 815 if (result == null) { 816 cachedHierarchy = result = makeHierarchy(); 817 } 818 return result; 819 } 820 821 private List<ObjectStreamClass> makeHierarchy() { 822 ArrayList<ObjectStreamClass> result = new ArrayList<ObjectStreamClass>(); 823 for (ObjectStreamClass osc = this; osc != null; osc = osc.getSuperclass()) { 824 result.add(0, osc); 825 } 826 return result; 827 } 828 829 /** 830 * If a Class uses "serialPersistentFields" to define the serialized fields, 831 * this.loadFields cannot get the "unshared" information when deserializing 832 * fields using current implementation of ObjectInputStream. This method 833 * provides a way to copy the "unshared" attribute from this.fields. 834 * 835 */ 836 private void copyFieldAttributes() { 837 if ((loadFields == null) || fields == null) { 838 return; 839 } 840 841 for (int i = 0; i < loadFields.length; i++) { 842 ObjectStreamField loadField = loadFields[i]; 843 String name = loadField.getName(); 844 for (int j = 0; j < fields.length; j++) { 845 ObjectStreamField field = fields[j]; 846 if (name.equals(field.getName())) { 847 loadField.setUnshared(field.isUnshared()); 848 loadField.setOffset(field.getOffset()); 849 break; 850 } 851 } 852 } 853 } 854 855 /** 856 * Returns the collection of field descriptors for the input fields of the 857 * corresponding class 858 * 859 * @return the receiver's collection of input fields for the class it 860 * represents 861 */ 862 ObjectStreamField[] getLoadFields() { 863 return loadFields; 864 } 865 866 /** 867 * Return a String representing the signature for a field {@code f}. 868 * 869 * @param f 870 * a java.lang.reflect.Field for which to compute the signature 871 * @return the field's signature 872 */ 873 private static native String getFieldSignature(Field f); 874 875 /** 876 * Returns the flags for this descriptor, where possible combined values are 877 * 878 * ObjectStreamConstants.SC_WRITE_METHOD 879 * ObjectStreamConstants.SC_SERIALIZABLE 880 * ObjectStreamConstants.SC_EXTERNALIZABLE 881 * 882 * @return byte the receiver's flags for the class it represents 883 */ 884 byte getFlags() { 885 return flags; 886 } 887 888 /** 889 * Return a String representing the signature for a method {@code m}. 890 * 891 * @param m 892 * a java.lang.reflect.Method for which to compute the signature 893 * @return the method's signature 894 */ 895 static native String getMethodSignature(Method m); 896 897 /** 898 * Returns the name of the class represented by this descriptor. 899 * 900 * @return the fully qualified name of the class this descriptor represents. 901 */ 902 public String getName() { 903 return className; 904 } 905 906 /** 907 * Returns the Serial Version User ID of the class represented by this 908 * descriptor. 909 * 910 * @return the SUID for the class represented by this descriptor. 911 */ 912 public long getSerialVersionUID() { 913 return svUID; 914 } 915 916 /** 917 * Returns the descriptor (ObjectStreamClass) of the superclass of the class 918 * represented by the receiver. 919 * 920 * @return an ObjectStreamClass representing the superclass of the class 921 * represented by the receiver. 922 */ 923 ObjectStreamClass getSuperclass() { 924 return superclass; 925 } 926 927 /** 928 * Return true if the given class {@code cl} has the 929 * compiler-generated method {@code clinit}. Even though it is 930 * compiler-generated, it is used by the serialization code to compute SUID. 931 * This is unfortunate, since it may depend on compiler optimizations in 932 * some cases. 933 * 934 * @param cl 935 * a java.lang.Class which to test 936 * @return {@code true} if the class has <clinit> {@code false} 937 * if the class does not have <clinit> 938 */ 939 private static native boolean hasClinit(Class<?> cl); 940 941 /** 942 * Return true if instances of class {@code cl} are Externalizable, 943 * false otherwise. 944 * 945 * @param cl 946 * a java.lang.Class which to test 947 * @return {@code true} if instances of the class are Externalizable 948 * {@code false} if instances of the class are not 949 * Externalizable 950 * 951 * @see Object#hashCode 952 */ 953 static boolean isExternalizable(Class<?> cl) { 954 return EXTERNALIZABLE.isAssignableFrom(cl); 955 } 956 957 /** 958 * Return true if the type code 959 * <code>typecode<code> describes a primitive type 960 * 961 * @param typecode a char describing the typecode 962 * @return {@code true} if the typecode represents a primitive type 963 * {@code false} if the typecode represents an Object type (including arrays) 964 * 965 * @see Object#hashCode 966 */ 967 static boolean isPrimitiveType(char typecode) { 968 return !(typecode == '[' || typecode == 'L'); 969 } 970 971 /** 972 * Return true if instances of class {@code cl} are Serializable, 973 * false otherwise. 974 * 975 * @param cl 976 * a java.lang.Class which to test 977 * @return {@code true} if instances of the class are Serializable 978 * {@code false} if instances of the class are not 979 * Serializable 980 * 981 * @see Object#hashCode 982 */ 983 static boolean isSerializable(Class<?> cl) { 984 return SERIALIZABLE.isAssignableFrom(cl); 985 } 986 987 /** 988 * Resolves the class properties, if they weren't already 989 */ 990 private void resolveProperties() { 991 if (arePropertiesResolved) { 992 return; 993 } 994 995 Class<?> cl = forClass(); 996 isProxy = Proxy.isProxyClass(cl); 997 isEnum = Enum.class.isAssignableFrom(cl); 998 isSerializable = isSerializable(cl); 999 isExternalizable = isExternalizable(cl); 1000 1001 arePropertiesResolved = true; 1002 } 1003 1004 boolean isSerializable() { 1005 resolveProperties(); 1006 return isSerializable; 1007 } 1008 1009 boolean isExternalizable() { 1010 resolveProperties(); 1011 return isExternalizable; 1012 } 1013 1014 boolean isProxy() { 1015 resolveProperties(); 1016 return isProxy; 1017 } 1018 1019 boolean isEnum() { 1020 resolveProperties(); 1021 return isEnum; 1022 } 1023 1024 /** 1025 * Returns the descriptor for a serializable class. 1026 * Returns null if the class doesn't implement {@code Serializable} or {@code Externalizable}. 1027 * 1028 * @param cl 1029 * a java.lang.Class for which to obtain the corresponding 1030 * descriptor 1031 * @return the corresponding descriptor if the class is serializable or 1032 * externalizable; null otherwise. 1033 */ 1034 public static ObjectStreamClass lookup(Class<?> cl) { 1035 ObjectStreamClass osc = lookupStreamClass(cl); 1036 return (osc.isSerializable() || osc.isExternalizable()) ? osc : null; 1037 } 1038 1039 /** 1040 * Returns the descriptor for any class, whether or not the class 1041 * implements Serializable or Externalizable. 1042 * 1043 * @param cl 1044 * a java.lang.Class for which to obtain the corresponding 1045 * descriptor 1046 * @return the descriptor 1047 * @since 1.6 1048 */ 1049 public static ObjectStreamClass lookupAny(Class<?> cl) { 1050 return lookupStreamClass(cl); 1051 } 1052 1053 /** 1054 * Return the descriptor (ObjectStreamClass) corresponding to the class 1055 * {@code cl}. Returns an ObjectStreamClass even if instances of the 1056 * class cannot be serialized 1057 * 1058 * @param cl 1059 * a java.langClass for which to obtain the corresponding 1060 * descriptor 1061 * @return the corresponding descriptor 1062 */ 1063 static ObjectStreamClass lookupStreamClass(Class<?> cl) { 1064 WeakHashMap<Class<?>, ObjectStreamClass> tlc = getCache(); 1065 ObjectStreamClass cachedValue = tlc.get(cl); 1066 if (cachedValue == null) { 1067 cachedValue = createClassDesc(cl); 1068 tlc.put(cl, cachedValue); 1069 } 1070 return cachedValue; 1071 1072 } 1073 1074 /** 1075 * A ThreadLocal cache for lookupStreamClass, with the possibility of discarding the thread 1076 * local storage content when the heap is exhausted. 1077 */ 1078 private static SoftReference<ThreadLocal<WeakHashMap<Class<?>, ObjectStreamClass>>> storage = 1079 new SoftReference<ThreadLocal<WeakHashMap<Class<?>, ObjectStreamClass>>>(null); 1080 1081 private static WeakHashMap<Class<?>, ObjectStreamClass> getCache() { 1082 ThreadLocal<WeakHashMap<Class<?>, ObjectStreamClass>> tls = storage.get(); 1083 if (tls == null) { 1084 tls = new ThreadLocal<WeakHashMap<Class<?>, ObjectStreamClass>>() { 1085 public WeakHashMap<Class<?>, ObjectStreamClass> initialValue() { 1086 return new WeakHashMap<Class<?>, ObjectStreamClass>(); 1087 } 1088 }; 1089 storage = new SoftReference<ThreadLocal<WeakHashMap<Class<?>, ObjectStreamClass>>>(tls); 1090 } 1091 return tls.get(); 1092 } 1093 1094 /** 1095 * Return the java.lang.reflect.Method if class <code>cl</code> implements 1096 * <code>methodName</code> . Return null otherwise. 1097 * 1098 * @param cl 1099 * a java.lang.Class which to test 1100 * @return <code>java.lang.reflect.Method</code> if the class implements 1101 * writeReplace <code>null</code> if the class does not implement 1102 * writeReplace 1103 */ 1104 static Method findMethod(Class<?> cl, String methodName) { 1105 Class<?> search = cl; 1106 Method method = null; 1107 while (search != null) { 1108 try { 1109 method = search.getDeclaredMethod(methodName, (Class[]) null); 1110 if (search == cl 1111 || (method.getModifiers() & Modifier.PRIVATE) == 0) { 1112 method.setAccessible(true); 1113 return method; 1114 } 1115 } catch (NoSuchMethodException nsm) { 1116 } 1117 search = search.getSuperclass(); 1118 } 1119 return null; 1120 } 1121 1122 /** 1123 * Return the java.lang.reflect.Method if class <code>cl</code> implements 1124 * private <code>methodName</code> . Return null otherwise. 1125 * 1126 * @param cl 1127 * a java.lang.Class which to test 1128 * @return {@code java.lang.reflect.Method} if the class implements 1129 * writeReplace {@code null} if the class does not implement 1130 * writeReplace 1131 */ 1132 static Method findPrivateMethod(Class<?> cl, String methodName, 1133 Class<?>[] param) { 1134 try { 1135 Method method = cl.getDeclaredMethod(methodName, param); 1136 if (Modifier.isPrivate(method.getModifiers()) && method.getReturnType() == void.class) { 1137 method.setAccessible(true); 1138 return method; 1139 } 1140 } catch (NoSuchMethodException nsm) { 1141 // Ignored 1142 } 1143 return null; 1144 } 1145 1146 boolean hasMethodWriteReplace() { 1147 return (methodWriteReplace != null); 1148 } 1149 1150 Method getMethodWriteReplace() { 1151 return methodWriteReplace; 1152 } 1153 1154 boolean hasMethodReadResolve() { 1155 return (methodReadResolve != null); 1156 } 1157 1158 Method getMethodReadResolve() { 1159 return methodReadResolve; 1160 } 1161 1162 boolean hasMethodWriteObject() { 1163 return (methodWriteObject != null); 1164 } 1165 1166 Method getMethodWriteObject() { 1167 return methodWriteObject; 1168 } 1169 1170 boolean hasMethodReadObject() { 1171 return (methodReadObject != null); 1172 } 1173 1174 Method getMethodReadObject() { 1175 return methodReadObject; 1176 } 1177 1178 boolean hasMethodReadObjectNoData() { 1179 return (methodReadObjectNoData != null); 1180 } 1181 1182 Method getMethodReadObjectNoData() { 1183 return methodReadObjectNoData; 1184 } 1185 1186 void initPrivateFields(ObjectStreamClass desc) { 1187 methodWriteReplace = desc.methodWriteReplace; 1188 methodReadResolve = desc.methodReadResolve; 1189 methodWriteObject = desc.methodWriteObject; 1190 methodReadObject = desc.methodReadObject; 1191 methodReadObjectNoData = desc.methodReadObjectNoData; 1192 } 1193 1194 /** 1195 * Set the class (java.lang.Class) that the receiver represents 1196 * 1197 * @param c 1198 * aClass, the new class that the receiver describes 1199 */ 1200 void setClass(Class<?> c) { 1201 resolvedClass = c; 1202 } 1203 1204 /** 1205 * Set the collection of field descriptors for the fields of the 1206 * corresponding class 1207 * 1208 * @param f 1209 * ObjectStreamField[], the receiver's new collection of declared 1210 * fields for the class it represents 1211 */ 1212 void setFields(ObjectStreamField[] f) { 1213 fields = f; 1214 } 1215 1216 /** 1217 * Set the collection of field descriptors for the input fields of the 1218 * corresponding class 1219 * 1220 * @param f 1221 * ObjectStreamField[], the receiver's new collection of input 1222 * fields for the class it represents 1223 */ 1224 void setLoadFields(ObjectStreamField[] f) { 1225 loadFields = f; 1226 } 1227 1228 /** 1229 * Set the flags for this descriptor, where possible combined values are 1230 * 1231 * ObjectStreamConstants.SC_WRITE_METHOD 1232 * ObjectStreamConstants.SC_SERIALIZABLE 1233 * ObjectStreamConstants.SC_EXTERNALIZABLE 1234 * 1235 * @param b 1236 * byte, the receiver's new flags for the class it represents 1237 */ 1238 void setFlags(byte b) { 1239 flags = b; 1240 } 1241 1242 /** 1243 * Set the name of the class represented by the receiver 1244 * 1245 * @param newName 1246 * a String, the new fully qualified name of the class the 1247 * receiver represents 1248 */ 1249 void setName(String newName) { 1250 className = newName; 1251 } 1252 1253 /** 1254 * Set the Serial Version User ID of the class represented by the receiver 1255 * 1256 * @param l 1257 * a long, the new SUID for the class represented by the receiver 1258 */ 1259 void setSerialVersionUID(long l) { 1260 svUID = l; 1261 } 1262 1263 /** 1264 * Set the descriptor for the superclass of the class described by the 1265 * receiver 1266 * 1267 * @param c 1268 * an ObjectStreamClass, the new ObjectStreamClass for the 1269 * superclass of the class represented by the receiver 1270 */ 1271 void setSuperclass(ObjectStreamClass c) { 1272 superclass = c; 1273 } 1274 1275 private int primitiveSize(Class<?> type) { 1276 if (type == byte.class || type == boolean.class) { 1277 return 1; 1278 } 1279 if (type == short.class || type == char.class) { 1280 return 2; 1281 } 1282 if (type == int.class || type == float.class) { 1283 return 4; 1284 } 1285 if (type == long.class || type == double.class) { 1286 return 8; 1287 } 1288 throw new AssertionError(); 1289 } 1290 1291 /** 1292 * Returns a string containing a concise, human-readable description of this 1293 * descriptor. 1294 * 1295 * @return a printable representation of this descriptor. 1296 */ 1297 @Override 1298 public String toString() { 1299 return getName() + ": static final long serialVersionUID =" + getSerialVersionUID() + "L;"; 1300 } 1301 } 1302