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