1. /*
  2. * @(#)ObjectStreamClass.java 1.98 00/02/02
  3. *
  4. * Copyright 1996-2000 Sun Microsystems, Inc. All Rights Reserved.
  5. *
  6. * This software is the proprietary information of Sun Microsystems, Inc.
  7. * Use is subject to license terms.
  8. *
  9. */
  10. package java.io;
  11. import java.security.MessageDigest;
  12. import java.security.NoSuchAlgorithmException;
  13. import java.security.DigestOutputStream;
  14. import java.security.AccessController;
  15. import java.security.PrivilegedAction;
  16. import java.lang.reflect.AccessibleObject;
  17. import java.lang.reflect.Modifier;
  18. import java.lang.reflect.Field;
  19. import java.lang.reflect.Member;
  20. import java.lang.reflect.Method;
  21. import java.lang.reflect.Constructor;
  22. import java.lang.reflect.Proxy;
  23. import java.util.Arrays;
  24. import java.util.Comparator;
  25. import java.util.Iterator;
  26. /**
  27. * Serialization's descriptor for classes.
  28. * It contains the name and serialVersionUID of the class.
  29. * <br>
  30. * The ObjectStreamClass for a specific class loaded in this Java VM can
  31. * be found/created using the lookup method.<p>
  32. * The algorithm to compute the SerialVersionUID is described in
  33. * <a href="../../../guide/serialization/spec/class.doc4.html"> Object Serialization Specification, Section 4.4, Stream Unique Identifiers</a>.
  34. *
  35. * @author Roger Riggs
  36. * @version 1.98 02/02/00
  37. * @see ObjectStreamField
  38. * @see <a href="../../../guide/serialization/spec/class.doc.html"> Object Serialization Specification, Section 4, Class Descriptors</a>
  39. * @since JDK1.1
  40. */
  41. public class ObjectStreamClass implements java.io.Serializable {
  42. /**
  43. * Find the descriptor for a class that can be serialized.
  44. * Creates an ObjectStreamClass instance if one does not exist
  45. * yet for class. Null is returned if the specified class does not
  46. * implement java.io.Serializable or java.io.Externalizable.
  47. *
  48. * @param cl class for which to get the descriptor
  49. * @return the class descriptor for the specified class
  50. */
  51. public static ObjectStreamClass lookup(Class cl)
  52. {
  53. ObjectStreamClass desc = lookupInternal(cl);
  54. if (desc.isSerializable() || desc.isExternalizable())
  55. return desc;
  56. return null;
  57. }
  58. /*
  59. * Find the class descriptor for the specified class.
  60. * Package access only so it can be called from ObjectIn/OutStream.
  61. */
  62. static ObjectStreamClass lookupInternal(Class cl)
  63. {
  64. /* Synchronize on the hashtable so no two threads will do
  65. * this at the same time.
  66. */
  67. ObjectStreamClass desc = null;
  68. synchronized (descriptorFor) {
  69. /* Find the matching descriptor if it already known */
  70. desc = findDescriptorFor(cl);
  71. if (desc == null) {
  72. /* Check if it's serializable */
  73. boolean serializable = Serializable.class.isAssignableFrom(cl);
  74. /* If the class is only Serializable,
  75. * lookup the descriptor for the superclass.
  76. */
  77. ObjectStreamClass superdesc = null;
  78. if (serializable) {
  79. Class superclass = cl.getSuperclass();
  80. if (superclass != null)
  81. superdesc = lookup(superclass);
  82. }
  83. /* Check if its' externalizable.
  84. * If it's Externalizable, clear the serializable flag.
  85. * Only one or the other may be set in the protocol.
  86. */
  87. boolean externalizable = false;
  88. if (serializable) {
  89. externalizable =
  90. ((superdesc != null) && superdesc.isExternalizable()) ||
  91. Externalizable.class.isAssignableFrom(cl);
  92. if (externalizable) {
  93. serializable = false;
  94. }
  95. }
  96. /* Create a new version descriptor,
  97. * it put itself in the known table.
  98. */
  99. desc = new ObjectStreamClass(cl, superdesc,
  100. serializable, externalizable);
  101. }
  102. }
  103. desc.init();
  104. return desc;
  105. }
  106. /**
  107. * The name of the class described by this descriptor.
  108. *
  109. * @return a <code>String</code> representing the fully qualified name of
  110. * the class
  111. */
  112. public String getName() {
  113. return name;
  114. }
  115. /**
  116. * Return the serialVersionUID for this class.
  117. * The serialVersionUID defines a set of classes all with the same name
  118. * that have evolved from a common root class and agree to be serialized
  119. * and deserialized using a common format.
  120. * NonSerializable classes have a serialVersionUID of 0L.
  121. *
  122. * @return the SUID of the class described by this descriptor
  123. */
  124. public long getSerialVersionUID() {
  125. return suid;
  126. }
  127. /**
  128. * Return the class in the local VM that this version is mapped to.
  129. * Null is returned if there is no corresponding local class.
  130. *
  131. * @return the <code>Class</code> instance that this descriptor represents
  132. */
  133. public Class forClass() {
  134. return ofClass;
  135. }
  136. /**
  137. * Return an array of the fields of this serializable class.
  138. *
  139. * @return an array containing an element for each persistent
  140. * field of this class. Returns an array of length zero if
  141. * there are no fields.
  142. * @since 1.2
  143. */
  144. public ObjectStreamField[] getFields() {
  145. // Return a copy so the caller can't change the fields.
  146. if (fields.length > 0) {
  147. ObjectStreamField[] dup = new ObjectStreamField[fields.length];
  148. System.arraycopy(fields, 0, dup, 0, fields.length);
  149. return dup;
  150. } else {
  151. return fields;
  152. }
  153. }
  154. /* Avoid unnecessary allocations within package. */
  155. final ObjectStreamField[] getFieldsNoCopy() {
  156. return fields;
  157. }
  158. /**
  159. * Get the field of this class by name.
  160. *
  161. * @param name the name of the data field to look for
  162. * @return The ObjectStreamField object of the named field or null if there
  163. * is no such named field.
  164. */
  165. public ObjectStreamField getField(String name) {
  166. ObjectStreamField searchKey =
  167. ObjectStreamField.constructSearchKey(name, Byte.TYPE);
  168. int index = -1;
  169. if (numObjFields != fields.length) {
  170. // perform binary search over primitive fields.
  171. index = Arrays.binarySearch(fields, searchKey);
  172. }
  173. if (index < 0 && numObjFields > 0) {
  174. // perform binary search over object fields. So passing false for
  175. // the isPrimitive flag.
  176. searchKey.setSearchKeyTypeString(false);
  177. index = Arrays.binarySearch(fields, searchKey);
  178. }
  179. return (index < 0) ? null : fields[index];
  180. }
  181. /**
  182. * Get the field of this class by name and fieldType.
  183. *
  184. * @param name the name of the data field to look for
  185. * @param fieldType the type of the data field
  186. * @return The ObjectStreamField object of the named field, type
  187. * or null if there is no such named field of fieldType.
  188. */
  189. ObjectStreamField getField(String name, Class fieldType) {
  190. ObjectStreamField searchKey =
  191. ObjectStreamField.constructSearchKey(name, fieldType);
  192. int index = Arrays.binarySearch(fields, searchKey);
  193. return (index < 0) ? null : fields[index];
  194. }
  195. /**
  196. * Return a string describing this ObjectStreamClass.
  197. */
  198. public String toString() {
  199. StringBuffer sb = new StringBuffer();
  200. sb.append(name);
  201. sb.append(": static final long serialVersionUID = ");
  202. sb.append(Long.toString(suid));
  203. sb.append("L;");
  204. return sb.toString();
  205. }
  206. /*
  207. * Create a new ObjectStreamClass from a loaded class.
  208. * Don't call this directly, call lookup instead.
  209. */
  210. private ObjectStreamClass(final Class cl, ObjectStreamClass superdesc,
  211. boolean serial, boolean extern)
  212. {
  213. ofClass = cl; /* created from this class */
  214. if (Proxy.isProxyClass(cl)) {
  215. forProxyClass = true;
  216. }
  217. name = cl.getName();
  218. superclass = superdesc;
  219. serializable = serial;
  220. if (!forProxyClass) {
  221. // proxy classes are never externalizable
  222. externalizable = extern;
  223. }
  224. /*
  225. * Enable block data mode by default. This is done to accommodate
  226. * ObjectInputStream subclasses which may override readClassDescriptor()
  227. * to obtain the class descriptor from ObjectStreamClass.lookup().
  228. */
  229. hasExternalizableBlockData = true;
  230. /*
  231. * Enter this class in the table of known descriptors.
  232. * Otherwise, when the fields are read it may recurse
  233. * trying to find the descriptor for itself.
  234. */
  235. insertDescriptorFor(this);
  236. /*
  237. * The remainder of initialization occurs in init(), which is called
  238. * after the lock on the global class descriptor table has been
  239. * released.
  240. */
  241. }
  242. /*
  243. * Initialize class descriptor. This method is only invoked on class
  244. * descriptors created via calls to lookupInternal(). This method is kept
  245. * separate from the ObjectStreamClass constructor so that lookupInternal
  246. * does not have to hold onto a global class descriptor table lock while the
  247. * class descriptor is being initialized (see bug 4165204).
  248. */
  249. private void init() {
  250. synchronized (lock) {
  251. final Class cl = ofClass;
  252. if (fields != null) // already initialized
  253. return;
  254. if (!serializable || externalizable || forProxyClass) {
  255. /*
  256. * Proxy classes never have serializable fields,
  257. * so short circuit expensive reflection lookup.
  258. */
  259. fields = NO_FIELDS;
  260. } else if (serializable) {
  261. /* Ask for permission to override field access checks.
  262. */
  263. AccessController.doPrivileged(new PrivilegedAction() {
  264. public Object run() {
  265. /* Fill in the list of persistent fields. If it is
  266. * declared, use the declared serialPersistentFields.
  267. * Otherwise, extract the fields from the class itself.
  268. */
  269. try {
  270. Field pf =
  271. cl.getDeclaredField("serialPersistentFields");
  272. pf.setAccessible(true);
  273. ObjectStreamField[] f =
  274. (ObjectStreamField[])pf.get(cl);
  275. int mods = pf.getModifiers();
  276. // field must be private for security reasons.
  277. if (Modifier.isPrivate(mods) &&
  278. Modifier.isFinal(mods) &&
  279. Modifier.isStatic(mods)) {
  280. fields = f;
  281. }
  282. } catch (NoSuchFieldException e) {
  283. /* Thrown if serialPersistentField is not a data
  284. * member of the class.
  285. */
  286. fields = null;
  287. } catch (IllegalAccessException e) {
  288. fields = null;
  289. } catch (IllegalArgumentException e) {
  290. /* Thrown if the field serialPersistentField is not
  291. * static.
  292. */
  293. fields = null;
  294. } catch (ClassCastException e) {
  295. /* Thrown if a field serialPersistentField exists
  296. * but it is not of type ObjectStreamField.
  297. */
  298. fields = null;
  299. }
  300. if (fields == null) {
  301. /* Get all of the declared fields for this Class.
  302. * setAccessible on all fields so they can be
  303. * accessed later. Create a temporary
  304. * ObjectStreamField array to hold each non-static,
  305. * non-transient field. Then copy the temporary
  306. * array into an array of the correct size once the
  307. * number of fields is known.
  308. */
  309. Field[] actualfields = cl.getDeclaredFields();
  310. int numFields = 0;
  311. ObjectStreamField[] tempFields =
  312. new ObjectStreamField[actualfields.length];
  313. for (int i = 0; i < actualfields.length; i++) {
  314. int modifiers = actualfields[i].getModifiers();
  315. if (!Modifier.isStatic(modifiers) &&
  316. !Modifier.isTransient(modifiers)) {
  317. tempFields[numFields++] =
  318. new ObjectStreamField(actualfields[i]);
  319. }
  320. }
  321. fields = new ObjectStreamField[numFields];
  322. System.arraycopy(tempFields, 0, fields, 0,
  323. numFields);
  324. } else {
  325. /*
  326. * For each declared persistent field, look for an
  327. * actual reflected Field. If there is one, make
  328. * sure it's the correct type and cache it in the
  329. * ObjectStreamClass for that field.
  330. */
  331. for (int j = fields.length-1; j >= 0; j--) {
  332. try {
  333. Field reflField = cl.getDeclaredField(
  334. fields[j].getName());
  335. if (fields[j].getType() ==
  336. reflField.getType())
  337. {
  338. fields[j].setField(reflField);
  339. } else {
  340. // TBD: Flag this as error?
  341. }
  342. } catch (NoSuchFieldException e) {
  343. // Nothing to do
  344. }
  345. }
  346. }
  347. return null;
  348. }
  349. });
  350. if (fields.length > 1)
  351. Arrays.sort(fields);
  352. /* Set up field data for use while writing using the API api. */
  353. computeFieldInfo();
  354. }
  355. /* Get the serialVersionUID from the class.
  356. * It uses the access override mechanism so make sure
  357. * the field objects is only used here.
  358. *
  359. * NonSerializable classes have a serialVerisonUID of 0L.
  360. */
  361. if (isNonSerializable()) {
  362. suid = 0L;
  363. } else {
  364. // Lookup special Serializable members using reflection.
  365. AccessController.doPrivileged(new PrivilegedAction() {
  366. public Object run() {
  367. if (forProxyClass) {
  368. // proxy classes always have serialVersionUID of 0L
  369. suid = 0L;
  370. } else {
  371. try {
  372. Field f =
  373. cl.getDeclaredField("serialVersionUID");
  374. int mods = f.getModifiers();
  375. if (Modifier.isStatic(mods) &&
  376. Modifier.isFinal(mods))
  377. {
  378. f.setAccessible(true);
  379. suid = f.getLong(cl);
  380. } else {
  381. suid = computeSerialVersionUID(cl);
  382. }
  383. } catch (NoSuchFieldException ex) {
  384. suid = computeSerialVersionUID(cl);
  385. } catch (IllegalAccessException ex) {
  386. suid = computeSerialVersionUID(cl);
  387. }
  388. }
  389. /* check for class provided substitution methods,
  390. * writeReplace and readResolve. Methods can not
  391. * be static.
  392. */
  393. writeReplaceMethod =
  394. getDeclaredMethod("writeReplace", NULL_ARGS,
  395. 0, Modifier.STATIC);
  396. if (writeReplaceMethod == null &&
  397. superclass != null &&
  398. checkSuperMethodAccess(
  399. superclass.writeReplaceMethod))
  400. {
  401. writeReplaceMethod = superclass.writeReplaceMethod;
  402. }
  403. readResolveMethod =
  404. getDeclaredMethod("readResolve", NULL_ARGS,
  405. 0, Modifier.STATIC);
  406. if (readResolveMethod == null && superclass != null &&
  407. checkSuperMethodAccess(
  408. superclass.readResolveMethod))
  409. {
  410. readResolveMethod = superclass.readResolveMethod;
  411. }
  412. /* Cache lookup of writeObject and readObject for
  413. * Serializable classes. (Do not lookup for
  414. * Externalizable)
  415. */
  416. if (serializable && !forProxyClass) {
  417. /* Work around compiler bug. See declaration for
  418. * more detail.
  419. */
  420. if (OOS_ARGS == null || OIS_ARGS == null) {
  421. initStaticMethodArgs();
  422. }
  423. writeObjectMethod =
  424. getDeclaredMethod("writeObject", OOS_ARGS,
  425. Modifier.PRIVATE, Modifier.STATIC);
  426. if (writeObjectMethod != null) {
  427. hasWriteObjectMethod = true;
  428. }
  429. readObjectMethod =
  430. getDeclaredMethod("readObject", OIS_ARGS,
  431. Modifier.PRIVATE, Modifier.STATIC);
  432. }
  433. return null;
  434. }
  435. });
  436. }
  437. }
  438. }
  439. /*
  440. * Create an empty ObjectStreamClass for a class about to be read.
  441. * This is separate from read so ObjectInputStream can assign the
  442. * wire handle early, before any nested ObjectStreamClass might
  443. * be read.
  444. */
  445. ObjectStreamClass(String n, long s) {
  446. name = n;
  447. suid = s;
  448. superclass = null;
  449. }
  450. /* Validate the compatibility of the stream class descriptor and
  451. * the specified local class.
  452. *
  453. * @exception InvalidClassException if stream and local class are
  454. * not compatible.
  455. */
  456. private void validateLocalClass(Class localCl) throws InvalidClassException {
  457. if (localClassDesc == null)
  458. throw new InvalidClassException(localCl.getName(),
  459. "Local class not compatible");
  460. if (suid != localClassDesc.suid) {
  461. /* Check for exceptional cases that allow mismatched suid. */
  462. /* Allow adding Serializable or Externalizable
  463. * to a later release of the class.
  464. */
  465. boolean addedSerialOrExtern =
  466. isNonSerializable() || localClassDesc.isNonSerializable();
  467. /* Disregard the suid of an array when name and localCl.Name differ.
  468. * If resolveClass() returns an array with a different package
  469. * name, the serialVersionUIDs will not match since the fully
  470. * qualified array class is used in the
  471. * computation of the array's serialVersionUID. There is
  472. * no way to set a permanent serialVersionUID for an array type.
  473. */
  474. boolean arraySUID = (localCl.isArray() && ! localCl.getName().equals(name));
  475. if (! arraySUID && ! addedSerialOrExtern ) {
  476. throw new InvalidClassException(localCl.getName(),
  477. "Local class not compatible:" +
  478. " stream classdesc serialVersionUID=" + suid +
  479. " local class serialVersionUID=" + localClassDesc.suid);
  480. }
  481. }
  482. /* compare the class names, stripping off package names. */
  483. if (! compareClassNames(name, localCl.getName(), '.'))
  484. throw new InvalidClassException(localCl.getName(),
  485. "Incompatible local class name. " +
  486. "Expected class name compatible with " +
  487. name);
  488. /*
  489. * Test that both implement either serializable or externalizable.
  490. */
  491. if ((serializable && localClassDesc.externalizable) ||
  492. (externalizable && localClassDesc.serializable))
  493. throw new InvalidClassException(localCl.getName(),
  494. "Serializable is incompatible with Externalizable");
  495. }
  496. /*
  497. * Set the local class that this stream class descriptor matches.
  498. * The base class name and serialization version id must match if
  499. * both classes are serializable.
  500. * Fill in the reflected Fields that will be used for reading.
  501. */
  502. void setClass(Class cl) throws InvalidClassException {
  503. /* Allow no local class implementation. Must be able to
  504. * skip objects in stream introduced by class evolution.
  505. */
  506. if (cl == null) {
  507. localClassDesc = null;
  508. ofClass = null;
  509. computeFieldInfo();
  510. return;
  511. }
  512. localClassDesc = lookupInternal(cl);
  513. validateLocalClass(cl);
  514. /* Disable instance deserialization when one class is serializable
  515. * and the other is not or if both the classes are neither serializable
  516. * nor externalizable.
  517. */
  518. if ((serializable != localClassDesc.serializable) ||
  519. (externalizable != localClassDesc.externalizable) ||
  520. (!serializable && !externalizable)) {
  521. /* Delay signaling InvalidClassException until trying
  522. * to deserialize an instance of this class. Allows
  523. * a previously nonSerialized class descriptor that was written
  524. * into the stream to be made Serializable
  525. * or Externalizable, in a later release.
  526. */
  527. disableInstanceDeserialization = true;
  528. ofClass = cl;
  529. return;
  530. }
  531. /* Set up the reflected Fields in the class where the value of each
  532. * field in this descriptor should be stored.
  533. * Each field in this ObjectStreamClass (the source) is located (by
  534. * name) in the ObjectStreamClass of the class(the destination).
  535. * In the usual (non-versioned case) the field is in both
  536. * descriptors and the types match, so the reflected Field is copied.
  537. * If the type does not match, a InvalidClass exception is thrown.
  538. * If the field is not present in the class, the reflected Field
  539. * remains null so the field will be read but discarded.
  540. * If extra fields are present in the class they are ignored. Their
  541. * values will be set to the default value by the object allocator.
  542. * Both the src and dest field list are sorted by type and name.
  543. */
  544. ObjectStreamField[] destfield =
  545. (ObjectStreamField[])localClassDesc.fields;
  546. ObjectStreamField[] srcfield =
  547. (ObjectStreamField[])fields;
  548. int j = 0;
  549. nextsrc:
  550. for (int i = 0; i < srcfield.length; i++ ) {
  551. /* Find this field in the dest*/
  552. for (int k = j; k < destfield.length; k++) {
  553. if (srcfield[i].getName().equals(destfield[k].getName())) {
  554. /* found match */
  555. if (srcfield[i].isPrimitive() &&
  556. !srcfield[i].typeEquals(destfield[k])) {
  557. throw new InvalidClassException(cl.getName(),
  558. "The type of field " +
  559. destfield[i].getName() +
  560. " of class " + name +
  561. " is incompatible.");
  562. }
  563. /* Skip over any fields in the dest that are not in the src */
  564. j = k;
  565. srcfield[i].setField(destfield[j].getField());
  566. // go on to the next source field
  567. continue nextsrc;
  568. }
  569. }
  570. }
  571. /* Remember the class this represents */
  572. ofClass = cl;
  573. /* Set up field data for use while reading from the input stream. */
  574. computeFieldInfo();
  575. /* get the cache of these methods from the local class
  576. * implementation.
  577. */
  578. readObjectMethod = localClassDesc.readObjectMethod;
  579. readResolveMethod = localClassDesc.readResolveMethod;
  580. }
  581. /* Compare the base class names of streamName and localName.
  582. *
  583. * @return Return true iff the base class name compare.
  584. * @parameter streamName Fully qualified class name.
  585. * @parameter localName Fully qualified class name.
  586. * @parameter pkgSeparator class names use either '.' or '/'.
  587. *
  588. * Only compare base class name to allow package renaming.
  589. */
  590. static boolean compareClassNames(String streamName,
  591. String localName,
  592. char pkgSeparator) {
  593. /* compare the class names, stripping off package names. */
  594. int streamNameIndex = streamName.lastIndexOf(pkgSeparator);
  595. if (streamNameIndex < 0)
  596. streamNameIndex = 0;
  597. int localNameIndex = localName.lastIndexOf(pkgSeparator);
  598. if (localNameIndex < 0)
  599. localNameIndex = 0;
  600. return streamName.regionMatches(false, streamNameIndex,
  601. localName, localNameIndex,
  602. streamName.length() - streamNameIndex);
  603. }
  604. /*
  605. * Compare the types of two class descriptors.
  606. * They match if they have the same class name and suid
  607. */
  608. boolean typeEquals(ObjectStreamClass other) {
  609. return (suid == other.suid) &&
  610. compareClassNames(name, other.name, '.');
  611. }
  612. /*
  613. * Return the superclass descriptor of this descriptor.
  614. */
  615. void setSuperclass(ObjectStreamClass s) {
  616. superclass = s;
  617. }
  618. /*
  619. * Return the superclass descriptor of this descriptor.
  620. */
  621. ObjectStreamClass getSuperclass() {
  622. return superclass;
  623. }
  624. /*
  625. * Return whether the class has a writeObject method
  626. */
  627. boolean hasWriteObject() {
  628. return hasWriteObjectMethod;
  629. }
  630. /*
  631. * Return true if all instances of 'this' Externalizable class
  632. * are written in block-data mode from the stream that 'this' was read
  633. * from. <p>
  634. *
  635. * In JDK 1.1, all Externalizable instances are not written
  636. * in block-data mode.
  637. * In the Java 2 SDK, all Externalizable instances, by default, are written
  638. * in block-data mode and the Externalizable instance is terminated with
  639. * tag TC_ENDBLOCKDATA. Change enabled the ability to skip Externalizable
  640. * instances.
  641. *
  642. * IMPLEMENTATION NOTE:
  643. * This should have been a mode maintained per stream; however,
  644. * for compatibility reasons, it was only possible to record
  645. * this change per class. All Externalizable classes within
  646. * a given stream should either have this mode enabled or
  647. * disabled. This is enforced by not allowing the PROTOCOL_VERSION
  648. * of a stream to he changed after any objects have been written.
  649. *
  650. * @see ObjectOuputStream#useProtocolVersion
  651. * @see ObjectStreamConstants#PROTOCOL_VERSION_1
  652. * @see ObjectStreamConstants#PROTOCOL_VERSION_2
  653. *
  654. * @since 1.2
  655. */
  656. boolean hasExternalizableBlockDataMode() {
  657. return hasExternalizableBlockData;
  658. }
  659. /*
  660. * Return the ObjectStreamClass of the local class this one is based on.
  661. */
  662. ObjectStreamClass localClassDescriptor() {
  663. return localClassDesc;
  664. }
  665. /*
  666. * Get the Serializability of the class.
  667. */
  668. boolean isSerializable() {
  669. return serializable;
  670. }
  671. /*
  672. * Get the externalizability of the class.
  673. */
  674. boolean isExternalizable() {
  675. return externalizable;
  676. }
  677. boolean isNonSerializable() {
  678. return ! (externalizable || serializable);
  679. }
  680. /*
  681. * Calculate the size of the array needed to store primitive data and the
  682. * number of object references to read when reading from the input
  683. * stream.
  684. */
  685. private void computeFieldInfo() {
  686. numPrimBytes = 0;
  687. numObjFields = 0;
  688. for (int i = 0; i < fields.length; i++ ) {
  689. switch (fields[i].getTypeCode()) {
  690. case 'B':
  691. case 'Z':
  692. fields[i].setOffset(numPrimBytes);
  693. numPrimBytes += 1;
  694. break;
  695. case 'C':
  696. case 'S':
  697. fields[i].setOffset(numPrimBytes);
  698. numPrimBytes += 2;
  699. break;
  700. case 'I':
  701. case 'F':
  702. fields[i].setOffset(numPrimBytes);
  703. numPrimBytes += 4;
  704. break;
  705. case 'J':
  706. case 'D' :
  707. fields[i].setOffset(numPrimBytes);
  708. numPrimBytes += 8;
  709. break;
  710. case 'L':
  711. case '[':
  712. fields[i].setOffset(numObjFields);
  713. numObjFields += 1;
  714. break;
  715. }
  716. }
  717. /* if this descriptor is bound to a class, obtain field IDs and
  718. * associated info.
  719. */
  720. if (ofClass != null) {
  721. int numPrimFields = fields.length - numObjFields;
  722. if (numPrimFields > 0) {
  723. primFieldIDs = new long[numPrimFields];
  724. primFieldTypecodes = new char[numPrimFields];
  725. }
  726. if (numObjFields > 0) {
  727. objFieldIDs = new long[numObjFields];
  728. objFieldTypes = new Class[numObjFields];
  729. }
  730. getFieldIDs(fields, primFieldIDs, objFieldIDs);
  731. int oi = 0, pi = 0;
  732. try {
  733. for (int i = 0; i < fields.length; i++) {
  734. char tc = fields[i].getTypeCode();
  735. switch (tc) {
  736. case 'L':
  737. case '[':
  738. {
  739. Field f = fields[i].getField();
  740. objFieldTypes[oi++] = (f != null) ?
  741. f.getType() : null;
  742. }
  743. break;
  744. default:
  745. primFieldTypecodes[pi++] = tc;
  746. break;
  747. }
  748. }
  749. } catch (ArrayIndexOutOfBoundsException e) {
  750. throw new InternalError("field count mismatch for class " +
  751. ofClass.getName());
  752. }
  753. if (oi != numObjFields || pi != numPrimFields) {
  754. throw new InternalError("field count mismatch for class " +
  755. ofClass.getName());
  756. }
  757. }
  758. }
  759. /*
  760. * Compute a hash for the specified class. Incrementally add
  761. * items to the hash accumulating in the digest stream.
  762. * Fold the hash into a long. Use the SHA secure hash function.
  763. */
  764. private static long computeSerialVersionUID(Class cl) {
  765. ByteArrayOutputStream devnull = new ByteArrayOutputStream(512);
  766. long h = 0;
  767. try {
  768. MessageDigest md = MessageDigest.getInstance("SHA");
  769. DigestOutputStream mdo = new DigestOutputStream(devnull, md);
  770. DataOutputStream data = new DataOutputStream(mdo);
  771. data.writeUTF(cl.getName());
  772. int classaccess = cl.getModifiers();
  773. classaccess &= (Modifier.PUBLIC | Modifier.FINAL |
  774. Modifier.INTERFACE | Modifier.ABSTRACT);
  775. /* Workaround for javac bug that only set ABSTRACT for
  776. * interfaces if the interface had some methods.
  777. * The ABSTRACT bit reflects that the number of methods > 0.
  778. * This is required so correct hashes can be computed
  779. * for existing class files.
  780. * Previously this hack was previously present in the VM.
  781. */
  782. Method[] method = cl.getDeclaredMethods();
  783. if ((classaccess & Modifier.INTERFACE) != 0) {
  784. classaccess &= (~Modifier.ABSTRACT);
  785. if (method.length > 0) {
  786. classaccess |= Modifier.ABSTRACT;
  787. }
  788. }
  789. data.writeInt(classaccess);
  790. /*
  791. * Get the list of interfaces supported,
  792. * Accumulate their names in Lexical order
  793. * and add them to the hash
  794. */
  795. if (!cl.isArray()) {
  796. /* In 1.2fcs, getInterfaces() was modified to return
  797. * {java.lang.Cloneable, java.io.Serializable} when
  798. * called on array classes. These values would upset
  799. * the computation of the hash, so we explicitly omit
  800. * them from its computation.
  801. */
  802. Class interfaces[] = cl.getInterfaces();
  803. Arrays.sort(interfaces, compareClassByName);
  804. for (int i = 0; i < interfaces.length; i++) {
  805. data.writeUTF(interfaces[i].getName());
  806. }
  807. }
  808. /* Sort the field names to get a deterministic order */
  809. Field[] field = cl.getDeclaredFields();
  810. Arrays.sort(field, compareMemberByName);
  811. for (int i = 0; i < field.length; i++) {
  812. Field f = field[i];
  813. /* Include in the hash all fields except those that are
  814. * private transient and private static.
  815. */
  816. int m = f.getModifiers();
  817. if (Modifier.isPrivate(m) &&
  818. (Modifier.isTransient(m) || Modifier.isStatic(m)))
  819. continue;
  820. data.writeUTF(f.getName());
  821. data.writeInt(m);
  822. data.writeUTF(getSignature(f.getType()));
  823. }
  824. if (hasStaticInitializer(cl)) {
  825. data.writeUTF("<clinit>");
  826. data.writeInt(Modifier.STATIC); // TBD: what modifiers does it have
  827. data.writeUTF("()V");
  828. }
  829. /*
  830. * Get the list of constructors including name and signature
  831. * Sort lexically, add all except the private constructors
  832. * to the hash with their access flags
  833. */
  834. MethodSignature[] constructors =
  835. MethodSignature.removePrivateAndSort(cl.getDeclaredConstructors());
  836. for (int i = 0; i < constructors.length; i++) {
  837. MethodSignature c = constructors[i];
  838. String mname = "<init>";
  839. String desc = c.signature;
  840. desc = desc.replace('/', '.');
  841. data.writeUTF(mname);
  842. data.writeInt(c.member.getModifiers());
  843. data.writeUTF(desc);
  844. }
  845. /* Include in the hash all methods except those that are
  846. * private transient and private static.
  847. */
  848. MethodSignature[] methods =
  849. MethodSignature.removePrivateAndSort(method);
  850. for (int i = 0; i < methods.length; i++ ) {
  851. MethodSignature m = methods[i];
  852. String desc = m.signature;
  853. desc = desc.replace('/', '.');
  854. data.writeUTF(m.member.getName());
  855. data.writeInt(m.member.getModifiers());
  856. data.writeUTF(desc);
  857. }
  858. /* Compute the hash value for this class.
  859. * Use only the first 64 bits of the hash.
  860. */
  861. data.flush();
  862. byte hasharray[] = md.digest();
  863. for (int i = 0; i < Math.min(8, hasharray.length); i++) {
  864. h += (long)(hasharray[i] & 255) << (i * 8);
  865. }
  866. } catch (IOException ignore) {
  867. /* can't happen, but be deterministic anyway. */
  868. h = -1;
  869. } catch (NoSuchAlgorithmException complain) {
  870. throw new SecurityException(complain.getMessage());
  871. }
  872. return h;
  873. }
  874. /**
  875. * Compute the JVM signature for the class.
  876. */
  877. static String getSignature(Class clazz) {
  878. String type = null;
  879. if (clazz.isArray()) {
  880. Class cl = clazz;
  881. int dimensions = 0;
  882. while (cl.isArray()) {
  883. dimensions++;
  884. cl = cl.getComponentType();
  885. }
  886. StringBuffer sb = new StringBuffer();
  887. for (int i = 0; i < dimensions; i++) {
  888. sb.append("[");
  889. }
  890. sb.append(getSignature(cl));
  891. type = sb.toString();
  892. } else if (clazz.isPrimitive()) {
  893. if (clazz == Integer.TYPE) {
  894. type = "I";
  895. } else if (clazz == Byte.TYPE) {
  896. type = "B";
  897. } else if (clazz == Long.TYPE) {
  898. type = "J";
  899. } else if (clazz == Float.TYPE) {
  900. type = "F";
  901. } else if (clazz == Double.TYPE) {
  902. type = "D";
  903. } else if (clazz == Short.TYPE) {
  904. type = "S";
  905. } else if (clazz == Character.TYPE) {
  906. type = "C";
  907. } else if (clazz == Boolean.TYPE) {
  908. type = "Z";
  909. } else if (clazz == Void.TYPE) {
  910. type = "V";
  911. }
  912. } else {
  913. type = "L" + clazz.getName().replace('.', '/') + ";";
  914. }
  915. return type;
  916. }
  917. /*
  918. * Compute the JVM method descriptor for the method.
  919. */
  920. static String getSignature(Method meth) {
  921. StringBuffer sb = new StringBuffer();
  922. sb.append("(");
  923. Class[] params = meth.getParameterTypes(); // avoid clone
  924. for (int j = 0; j < params.length; j++) {
  925. sb.append(getSignature(params[j]));
  926. }
  927. sb.append(")");
  928. sb.append(getSignature(meth.getReturnType()));
  929. return sb.toString();
  930. }
  931. /*
  932. * Compute the JVM constructor descriptor for the constructor.
  933. */
  934. static String getSignature(Constructor cons) {
  935. StringBuffer sb = new StringBuffer();
  936. sb.append("(");
  937. Class[] params = cons.getParameterTypes(); // avoid clone
  938. for (int j = 0; j < params.length; j++) {
  939. sb.append(getSignature(params[j]));
  940. }
  941. sb.append(")V");
  942. return sb.toString();
  943. }
  944. /*
  945. * locate the ObjectStreamClass for this class and write it to the stream.
  946. *
  947. * @serialData
  948. * <code>primitive UTF-8 String</code> Qalified class name.
  949. * <code>long</code> Serial version unique identifier for compatible classes.
  950. * <code>byte</code>. Mask with <code>java.io.ObjectStreamConstants.SC_*</code>.<br>
  951. * <code>short</code>. Number of Serializable fields to follow. If 0, no more data.
  952. * <code>list of Serializable Field descriptors</code>. Descriptors for Primitive
  953. * typed fields are written first sorted by field name
  954. * followed by descriptors for the object typed fields sorted
  955. * by field name. The names are sorted using String.compareTo.
  956. *
  957. * A Serializable field consists of the following data:
  958. * <code>byte</code> TypeCode of field. See ObjectStreamField.getTypeCode().
  959. * <code>primitive UTF-8 encoded String</code> Unqualified name of field.
  960. * <code>String</code> Qualified class name.
  961. */
  962. void write(ObjectOutputStream s) throws IOException {
  963. /* write the flag indicating that this class has write/read object methods */
  964. int flags = 0;
  965. if (hasWriteObjectMethod)
  966. flags |= ObjectStreamConstants.SC_WRITE_METHOD;
  967. if (serializable)
  968. flags |= ObjectStreamConstants.SC_SERIALIZABLE;
  969. if (externalizable) {
  970. flags |= ObjectStreamConstants.SC_EXTERNALIZABLE;
  971. /* Enabling the SC_BLOCK_DATA flag indicates PROTCOL_VERSION_2.*/
  972. if (! s.useDeprecatedExternalizableFormat)
  973. flags |= ObjectStreamConstants.SC_BLOCK_DATA;
  974. }
  975. s.writeByte(flags);
  976. // If there are no fields, write a null and return
  977. if (fields == null) {
  978. s.writeShort(0);
  979. return;
  980. }
  981. /* write the total number of fields */
  982. s.writeShort(fields.length);
  983. /* Write out the descriptors of the primitive fields Each
  984. * descriptor consists of the UTF fieldname, a short for the
  985. * access modes, and the first byte of the signature byte.
  986. * For the object types, ('[' and 'L'), a reference to the
  987. * type of the field follows.
  988. */
  989. for (int i = 0; i < fields.length; i++ ) {
  990. ObjectStreamField f = fields[i];
  991. s.writeByte(f.getTypeCode());
  992. s.writeUTF(f.getName());
  993. if (!f.isPrimitive()) {
  994. s.writeTypeString(f.getTypeString());
  995. }
  996. }
  997. }
  998. /*
  999. * Read the version descriptor from the stream.
  1000. * Write the count of field descriptors
  1001. * for each descriptor write the first character of its type,
  1002. * the name of the field.
  1003. * If the type is for an object either array or object, write
  1004. * the type typedescriptor for the type
  1005. */
  1006. void read(ObjectInputStream s) throws IOException, ClassNotFoundException {
  1007. /* read flags and determine whether the source class had
  1008. * write/read methods.
  1009. */
  1010. byte flags = s.readByte();
  1011. serializable = (flags & ObjectStreamConstants.SC_SERIALIZABLE) != 0;
  1012. externalizable = (flags & ObjectStreamConstants.SC_EXTERNALIZABLE) != 0;
  1013. hasWriteObjectMethod = serializable ?
  1014. (flags & ObjectStreamConstants.SC_WRITE_METHOD) != 0 :
  1015. false;
  1016. hasExternalizableBlockData = externalizable ?
  1017. (flags & ObjectStreamConstants.SC_BLOCK_DATA) != 0 :
  1018. false;
  1019. /* Read the number of fields described.
  1020. * For each field read the type byte, the name.
  1021. */
  1022. int count = s.readShort();
  1023. fields = new ObjectStreamField[count];
  1024. /* disable replacement of String objects read
  1025. * by ObjectStreamClass. */
  1026. boolean prevEnableResolve = s.enableResolve;
  1027. s.enableResolve = false;
  1028. try {
  1029. for (int i = 0; i < count; i++ ) {
  1030. char type = (char)s.readByte();
  1031. String name = s.readUTF();
  1032. String ftype = null;
  1033. switch (type) {
  1034. case '[':
  1035. case 'L':
  1036. ftype = (String) s.readObject();
  1037. break;
  1038. case 'Z':
  1039. case 'B':
  1040. case 'C':
  1041. case 'S':
  1042. case 'I':
  1043. case 'J':
  1044. case 'F':
  1045. case 'D':
  1046. break;
  1047. default:
  1048. throw new StreamCorruptedException("illegal field " +
  1049. "descriptor typecode: " + type);
  1050. }
  1051. fields[i] = new ObjectStreamField(name, type, null, ftype);
  1052. }
  1053. } finally {
  1054. s.enableResolve = prevEnableResolve;
  1055. }
  1056. }
  1057. /*
  1058. * Perform a light copy of the given class descriptor into this class
  1059. * descriptor: only copy members that would be copied if the descriptor were
  1060. * serialized to a stream and then read back out again. Used for class
  1061. * descriptor cacheing.
  1062. *
  1063. * Note that this method assumes it is being called on a newly-constructed
  1064. * ObjectStreamClass, so it doesn't bother to set all fields (e.g.,
  1065. * superclass, ofClass, numPrimBytes, etc.) which have already been
  1066. * initialized to their proper default values. Most of these are filled in
  1067. * when setClass() is called on this object.
  1068. */
  1069. void lightCopy(ObjectStreamClass desc) {
  1070. // copy essential members
  1071. name = desc.name;
  1072. serializable = desc.serializable;
  1073. externalizable = desc.externalizable;
  1074. fields = new ObjectStreamField[desc.fields.length];
  1075. for (int i = 0; i < fields.length; i++) {
  1076. ObjectStreamField cf = desc.fields[i];
  1077. fields[i] = new ObjectStreamField(cf.getName(),
  1078. cf.getTypeCode(), null, cf.getTypeString());
  1079. }
  1080. suid = desc.suid;
  1081. hasWriteObjectMethod = desc.hasWriteObjectMethod;
  1082. hasExternalizableBlockData = desc.hasExternalizableBlockData;
  1083. }
  1084. /**
  1085. * Initialize the contents of an incoming class descriptor for a
  1086. * proxy class.
  1087. *
  1088. * This method performs the equivalent of the read() method for proxy
  1089. * classes, for which the equivalent data is implicit rather than in
  1090. * the stream format for the class descriptor, and sets the name,
  1091. * which could not be determined when the descriptor object was
  1092. * constructed. Thus, this method prepares an incoming proxy class
  1093. * descriptor for the setClass() method.
  1094. */
  1095. void initProxyClassDesc(Class cl) {
  1096. forProxyClass = true;
  1097. if (cl != null) {
  1098. name = cl.getName();
  1099. }
  1100. serializable = true;
  1101. externalizable = false;
  1102. fields = ObjectStreamClass.NO_FIELDS;
  1103. hasWriteObjectMethod = false;
  1104. hasExternalizableBlockData = true;
  1105. }
  1106. /* To accomodate nonSerializable classes written into a stream,
  1107. * this check must be delayed until an instance is deserialized.
  1108. */
  1109. void verifyInstanceDeserialization() throws InvalidClassException {
  1110. if (disableInstanceDeserialization) {
  1111. String name = (serializable || externalizable) ?
  1112. localClassDesc.getName() : getName();
  1113. String stype = (serializable || localClassDesc.serializable) ?
  1114. "Serializable" :
  1115. (externalizable || localClassDesc.externalizable) ?
  1116. "Externalizable" : "Serializable or Externalizable";
  1117. throw new InvalidClassException(name, "is not " + stype);
  1118. }
  1119. }
  1120. /*
  1121. * Cache of Class -> ClassDescriptor Mappings.
  1122. */
  1123. static private ObjectStreamClassEntry[] descriptorFor = new ObjectStreamClassEntry[61];
  1124. /*
  1125. * findDescriptorFor a Class. This looks in the cache for a
  1126. * mapping from Class -> ObjectStreamClass mappings. The hashCode
  1127. * of the Class is used for the lookup since the Class is the key.
  1128. * The entries are extended from java.lang.ref.SoftReference so the
  1129. * gc will be able to free them if needed.
  1130. */
  1131. private static ObjectStreamClass findDescriptorFor(Class cl) {
  1132. int hash = cl.hashCode();
  1133. int index = (hash & 0x7FFFFFFF) % descriptorFor.length;
  1134. ObjectStreamClassEntry e;
  1135. ObjectStreamClassEntry prev;
  1136. /* Free any initial entries whose refs have been cleared */
  1137. while ((e = descriptorFor[index]) != null && e.get() == null) {
  1138. descriptorFor[index] = e.next;
  1139. }
  1140. /* Traverse the chain looking for a descriptor with ofClass == cl.
  1141. * unlink entries that are unresolved.
  1142. */
  1143. prev = e;
  1144. while (e != null ) {
  1145. ObjectStreamClass desc = (ObjectStreamClass)(e.get());
  1146. if (desc == null) {
  1147. // This entry has been cleared, unlink it
  1148. prev.next = e.next;
  1149. } else {
  1150. if (desc.ofClass == cl)
  1151. return desc;
  1152. prev = e;
  1153. }
  1154. e = e.next;
  1155. }
  1156. return null;
  1157. }
  1158. /*
  1159. * insertDescriptorFor a Class -> ObjectStreamClass mapping.
  1160. */
  1161. private static void insertDescriptorFor(ObjectStreamClass desc) {
  1162. // Make sure not already present
  1163. if (findDescriptorFor(desc.ofClass) != null) {
  1164. return;
  1165. }
  1166. int hash = desc.ofClass.hashCode();
  1167. int index = (hash & 0x7FFFFFFF) % descriptorFor.length;
  1168. ObjectStreamClassEntry e = new ObjectStreamClassEntry(desc);
  1169. e.next = descriptorFor[index];
  1170. descriptorFor[index] = e;
  1171. }
  1172. /*
  1173. * Initialize native code.
  1174. */
  1175. static {
  1176. initNative();
  1177. }
  1178. /*
  1179. * The name of this descriptor
  1180. */
  1181. private String name;
  1182. /*
  1183. * The descriptor of the supertype.
  1184. */
  1185. ObjectStreamClass superclass;
  1186. /*
  1187. * Flags for Serializable and Externalizable.
  1188. */
  1189. private boolean serializable;
  1190. private boolean externalizable;
  1191. /*
  1192. * Array of persistent fields of this class, sorted by
  1193. * type and name.
  1194. */
  1195. private ObjectStreamField[] fields;
  1196. /*
  1197. * Class that is a descriptor for in this virtual machine.
  1198. */
  1199. private Class ofClass;
  1200. /*
  1201. * True if descriptor for a proxy class.
  1202. */
  1203. boolean forProxyClass;
  1204. /*
  1205. * SerialVersionUID for this class.
  1206. */
  1207. private long suid;
  1208. /*
  1209. * The total number of bytes of primitive fields.
  1210. * The total number of object fields.
  1211. */
  1212. int numPrimBytes;
  1213. int numObjFields;
  1214. /* True if this class has/had a writeObject method */
  1215. private boolean hasWriteObjectMethod;
  1216. /* In JDK 1.1, external data was not written in block mode.
  1217. * As of the Java 2 SDK, external data is written in block data mode. This
  1218. * flag enables the Java 2 SDK to be able to read JDK 1.1 written external data.
  1219. *
  1220. * @since 1.2
  1221. */
  1222. private boolean hasExternalizableBlockData;
  1223. Method writeObjectMethod;
  1224. Method readObjectMethod;
  1225. Method readResolveMethod;
  1226. Method writeReplaceMethod;
  1227. /*
  1228. * ObjectStreamClass that this one was built from.
  1229. */
  1230. private ObjectStreamClass localClassDesc;
  1231. /* Indicates that stream and local class are not both
  1232. * serializable. No instances of this class can be deserialized.
  1233. */
  1234. private boolean disableInstanceDeserialization = false;
  1235. /* place to temporarily hold ClassNotFoundException thrown by
  1236. * ObjectInputStream.resolveClass().
  1237. */
  1238. ClassNotFoundException pendingException;
  1239. /* Class objects corresponding to this class descriptor and its super-class
  1240. * descriptors. ancestors[0] is the class which this descriptor maps to.
  1241. * ancestors[1..n] (where n is the number of super-class descriptors above
  1242. * this descriptor) contain the classes that the corresponding super-class
  1243. * descriptor maps to (or null if it has no equivalent in this vm).
  1244. * Finally, ancestors[n + 1] contains the uppermost ancestor, which is the
  1245. * lowest non-serializable superclass. This array is set by
  1246. * ObjectInputStream.inputObject() for Serializable, but not Externalizable,
  1247. * class descriptors.
  1248. */
  1249. Class[] ancestors;
  1250. /*
  1251. * IDs and typecodes (e.g., 'I', 'Z') for the primitive fields of the class
  1252. * this descriptor represents.
  1253. */
  1254. long[] primFieldIDs;
  1255. char[] primFieldTypecodes;
  1256. /*
  1257. * IDs and class types for the object fields of the class this descriptor
  1258. * represents.
  1259. */
  1260. long[] objFieldIDs;
  1261. Class[] objFieldTypes;
  1262. /* Internal lock object. */
  1263. private Object lock = new Object();
  1264. /*
  1265. * Initialize native code. Should be called once, at class initialization.
  1266. */
  1267. private static native void initNative();
  1268. /*
  1269. * Get the field IDs associated with the given fields. The field IDs are
  1270. * later passed as arguments to the various ObjectInputStream and
  1271. * ObjectOutputStream native methods for setting and getting field values.
  1272. */
  1273. private static native void getFieldIDs(ObjectStreamField[] fields,
  1274. long[] primFieldIDs, long[] objFieldIDs);
  1275. /* Find out if the class has a static class initializer <clinit> */
  1276. private static native boolean hasStaticInitializer(Class cl);
  1277. /** use serialVersionUID from JDK 1.1. for interoperability */
  1278. private static final long serialVersionUID = -6120832682080437368L;
  1279. /**
  1280. * Set serialPersistentFields of a Serializable class to this value to
  1281. * denote that the class has no Serializable fields.
  1282. */
  1283. public static final ObjectStreamField[] NO_FIELDS =
  1284. new ObjectStreamField[0];
  1285. /**
  1286. * Class ObjectStreamClass is special cased within the
  1287. * Serialization Stream Protocol.
  1288. *
  1289. * An ObjectStreamClass is written intially into an ObjectOutputStream
  1290. * in the following format:
  1291. * <pre>
  1292. * TC_CLASSDESC className, serialVersionUID, flags,
  1293. * length, list of field descriptions.
  1294. *
  1295. * FIELDNAME TYPES
  1296. * DESCRIPTION
  1297. * --------------------------------------
  1298. * className primitive data String
  1299. * Fully qualified class name.
  1300. *
  1301. * serialVersionUID long
  1302. * Stream Unique Identifier for compatible classes
  1303. * with same base class name.
  1304. *
  1305. * flags byte
  1306. * Attribute bit fields defined in
  1307. * <code>java.io.ObjectStreamConstants.SC_*</code>.
  1308. *
  1309. * length short
  1310. * The number of field descriptions to follow.
  1311. *
  1312. * fieldDescription (byte, primitive data String, String Object)
  1313. * A pseudo-externalized format of class
  1314. * <code>java.io.ObjectStreamField</code>.
  1315. * Consists of typeCode, fieldName, and,
  1316. * if a nonPrimitive typecode, a fully qualified
  1317. * class name. See <code>Class.getName</code> method
  1318. * for the typecode byte encodings.
  1319. * </pre>
  1320. * The first time the class descriptor
  1321. * is written into the stream, a new handle is generated.
  1322. * Future references to the class descriptor are
  1323. * written as references to the initial class descriptor instance.
  1324. *
  1325. * @see java.io.ObjectOutputStream#writeUTF(java.lang.String)
  1326. */
  1327. private static final ObjectStreamField[] serialPersistentFields =
  1328. NO_FIELDS;
  1329. /*
  1330. * Entries held in the Cache of known ObjectStreamClass objects.
  1331. * Entries are chained together with the same hash value (modulo array size).
  1332. */
  1333. private static class ObjectStreamClassEntry extends java.lang.ref.SoftReference
  1334. {
  1335. ObjectStreamClassEntry(ObjectStreamClass c) {
  1336. super(c);
  1337. }
  1338. ObjectStreamClassEntry next;
  1339. }
  1340. /*
  1341. * Comparator object for Classes and Interfaces
  1342. */
  1343. private static Comparator compareClassByName =
  1344. new CompareClassByName();
  1345. private static class CompareClassByName implements Comparator {
  1346. public int compare(Object o1, Object o2) {
  1347. Class c1 = (Class)o1;
  1348. Class c2 = (Class)o2;
  1349. return (c1.getName()).compareTo(c2.getName());
  1350. }
  1351. }
  1352. /*
  1353. * Comparator object for Members, Fields, and Methods
  1354. */
  1355. private static Comparator compareMemberByName =
  1356. new CompareMemberByName();
  1357. private static class CompareMemberByName implements Comparator {
  1358. public int compare(Object o1, Object o2) {
  1359. String s1 = ((Member)o1).getName();
  1360. String s2 = ((Member)o2).getName();
  1361. if (o1 instanceof Method) {
  1362. s1 += getSignature((Method)o1);
  1363. s2 += getSignature((Method)o2);
  1364. } else if (o1 instanceof Constructor) {
  1365. s1 += getSignature((Constructor)o1);
  1366. s2 += getSignature((Constructor)o2);
  1367. }
  1368. return s1.compareTo(s2);
  1369. }
  1370. }
  1371. /* It is expensive to recompute a method or constructor signature
  1372. many times, so compute it only once using this data structure. */
  1373. private static class MethodSignature implements Comparator {
  1374. Member member;
  1375. String signature; // cached parameter signature
  1376. /* Given an array of Method or Constructor members,
  1377. return a sorted array of the non-private members.*/
  1378. /* A better implementation would be to implement the returned data
  1379. structure as an insertion sorted link list.*/
  1380. static MethodSignature[] removePrivateAndSort(Member[] m) {
  1381. int numNonPrivate = 0;
  1382. for (int i = 0; i < m.length; i++) {
  1383. if (! Modifier.isPrivate(m[i].getModifiers())) {
  1384. numNonPrivate++;
  1385. }
  1386. }
  1387. MethodSignature[] cm = new MethodSignature[numNonPrivate];
  1388. int cmi = 0;
  1389. for (int i = 0; i < m.length; i++) {
  1390. if (! Modifier.isPrivate(m[i].getModifiers())) {
  1391. cm[cmi] = new MethodSignature(m[i]);
  1392. cmi++;
  1393. }
  1394. }
  1395. if (cmi > 0)
  1396. Arrays.sort(cm, cm[0]);
  1397. return cm;
  1398. }
  1399. /* Assumes that o1 and o2 are either both methods
  1400. or both constructors.*/
  1401. public int compare(Object o1, Object o2) {
  1402. /* Arrays.sort calls compare when o1 and o2 are equal.*/
  1403. if (o1 == o2)
  1404. return 0;
  1405. MethodSignature c1 = (MethodSignature)o1;
  1406. MethodSignature c2 = (MethodSignature)o2;
  1407. int result;
  1408. if (isConstructor()) {
  1409. result = c1.signature.compareTo(c2.signature);
  1410. } else { // is a Method.
  1411. result = c1.member.getName().compareTo(c2.member.getName());
  1412. if (result == 0)
  1413. result = c1.signature.compareTo(c2.signature);
  1414. }
  1415. return result;
  1416. }
  1417. private boolean isConstructor() {
  1418. return member instanceof Constructor;
  1419. }
  1420. private MethodSignature(Member m) {
  1421. member = m;
  1422. if (isConstructor()) {
  1423. signature = ObjectStreamClass.getSignature((Constructor)m);
  1424. } else {
  1425. signature = ObjectStreamClass.getSignature((Method)m);
  1426. }
  1427. }
  1428. }
  1429. boolean isResolvable() {
  1430. return readResolveMethod != null;
  1431. }
  1432. boolean isReplaceable() {
  1433. return writeReplaceMethod != null;
  1434. }
  1435. static Object invokeMethod(Method method, Object obj, Object[] args)
  1436. throws IOException
  1437. {
  1438. Object returnValue = null;
  1439. try {
  1440. returnValue = method.invoke(obj, args);
  1441. } catch (java.lang.reflect.InvocationTargetException e) {
  1442. Throwable t = e.getTargetException();
  1443. if (t instanceof IOException)
  1444. throw (IOException)t;
  1445. else if (t instanceof RuntimeException)
  1446. throw (RuntimeException) t;
  1447. else if (t instanceof Error)
  1448. throw (Error) t;
  1449. else
  1450. throw new Error("interal error");
  1451. } catch (IllegalAccessException e) {
  1452. // cannot happen
  1453. throw new Error("interal error");
  1454. }
  1455. return returnValue;
  1456. }
  1457. /* ASSUMPTION: Called within priviledged access block.
  1458. * Needed to set declared methods and to set the
  1459. * accessibility bit.
  1460. */
  1461. private Method getDeclaredMethod(String methodName, Class[] args,
  1462. int requiredModifierMask,
  1463. int disallowedModifierMask) {
  1464. Method method = null;
  1465. try {
  1466. method =
  1467. ofClass.getDeclaredMethod(methodName, args);
  1468. if (method != null) {
  1469. int mods = method.getModifiers();
  1470. if ((mods & disallowedModifierMask) != 0 ||
  1471. (mods & requiredModifierMask) != requiredModifierMask) {
  1472. method = null;
  1473. } else {
  1474. method.setAccessible(true);
  1475. }
  1476. }
  1477. } catch (NoSuchMethodException e) {
  1478. // Since it is alright if methodName does not exist,
  1479. // no need to do anything special here.
  1480. }
  1481. return method;
  1482. }
  1483. /*
  1484. * Return true if scMethod is accessible from the context of
  1485. * this ObjectStreamClass' local implementation class.
  1486. * Simulate java accessibility rules of accessing method 'scMethod'
  1487. * from a method within subclass this.forClass.
  1488. * If method would not be accessible, returns null.
  1489. *
  1490. * @param scMethod A method from the superclass of this ObjectStreamClass.
  1491. */
  1492. private boolean checkSuperMethodAccess(Method scMethod) {
  1493. if (scMethod == null) {
  1494. return false;
  1495. }
  1496. int supermods = scMethod.getModifiers();
  1497. if (Modifier.isPublic(supermods) || Modifier.isProtected(supermods)) {
  1498. return true;
  1499. } else if (Modifier.isPrivate(supermods)) {
  1500. return false;
  1501. } else {
  1502. // check package-private access.
  1503. return isSameClassPackage(scMethod.getDeclaringClass(), ofClass);
  1504. }
  1505. }
  1506. /* Will not work for array classes. */
  1507. static private boolean isSameClassPackage(Class cl1, Class cl2) {
  1508. if (cl1.getClassLoader() != cl2.getClassLoader()) {
  1509. return false;
  1510. } else {
  1511. String clName1 = cl1.getName();
  1512. String clName2 = cl2.getName();
  1513. int idx1 = clName1.lastIndexOf('.');
  1514. int idx2 = clName2.lastIndexOf('.');
  1515. if (idx1 == -1 || idx2 == -1) {
  1516. /* One of the two doesn't have a package. Only return true
  1517. * if the other one also does not have a package.
  1518. */
  1519. return idx1 == idx2;
  1520. } else {
  1521. return clName1.regionMatches(false, 0,
  1522. clName2, 0, idx1 - 1);
  1523. }
  1524. }
  1525. }
  1526. private final static Class[] NULL_ARGS = {};
  1527. //WORKAROUND compiler bug with following code.
  1528. //static final Class[] OIS_ARGS = {ObjectInpuStream.class};
  1529. //static final Class[] OOS_ARGS = {ObjectOutpuStream.class};
  1530. private static Class[] OIS_ARGS = null;
  1531. private static Class[] OOS_ARGS = null;
  1532. private static void initStaticMethodArgs() {
  1533. OOS_ARGS = new Class[1];
  1534. OOS_ARGS[0] = ObjectOutputStream.class;
  1535. OIS_ARGS = new Class[1];
  1536. OIS_ARGS[0] = ObjectInputStream.class;
  1537. }
  1538. }