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