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