1. /*
  2. * @(#)ObjectStreamClass_1_3_1.java 1.6 04/01/12
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. /*
  8. * Licensed Materials - Property of IBM
  9. * RMI-IIOP v1.0
  10. * Copyright IBM Corp. 1998 1999 All Rights Reserved
  11. *
  12. * US Government Users Restricted Rights - Use, duplication or
  13. * disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
  14. */
  15. package com.sun.corba.se.impl.orbutil;
  16. import java.security.MessageDigest;
  17. import java.security.NoSuchAlgorithmException;
  18. import java.security.DigestOutputStream;
  19. import java.security.AccessController;
  20. import java.security.PrivilegedExceptionAction;
  21. import java.security.PrivilegedActionException;
  22. import java.security.PrivilegedAction;
  23. import java.lang.reflect.Modifier;
  24. import java.lang.reflect.Array;
  25. import java.lang.reflect.Field;
  26. import java.lang.reflect.Member;
  27. import java.lang.reflect.Method;
  28. import java.lang.reflect.Constructor;
  29. import java.lang.reflect.Proxy;
  30. import java.lang.reflect.InvocationTargetException;
  31. import java.io.IOException;
  32. import java.io.DataOutputStream;
  33. import java.io.ByteArrayOutputStream;
  34. import java.io.InvalidClassException;
  35. import java.io.Serializable;
  36. import java.util.Arrays;
  37. import java.util.Comparator;
  38. import java.util.Hashtable;
  39. import org.omg.CORBA.ValueMember;
  40. import com.sun.corba.se.impl.io.ValueUtility;
  41. import com.sun.corba.se.impl.io.ObjectStreamClass;
  42. /**
  43. * This is duplicated here to preserve the JDK 1.3.1FCS behavior
  44. * of calculating the OMG hash code incorrectly when serialPersistentFields
  45. * is used, but some of the fields no longer exist in the class itself.
  46. *
  47. * We have to duplicate it since we aren't allowed to modify the
  48. * com.sun.corba.se.impl.io version further, and can't make it
  49. * public outside of its package for security reasons.
  50. */
  51. /**
  52. * A ObjectStreamClass_1_3_1 describes a class that can be serialized to a stream
  53. * or a class that was serialized to a stream. It contains the name
  54. * and the serialVersionUID of the class.
  55. * <br>
  56. * The ObjectStreamClass_1_3_1 for a specific class loaded in this Java VM can
  57. * be found using the lookup method.
  58. *
  59. * @author Roger Riggs
  60. * @(#)ObjectStreamClass_1_3_1.java 1.17 99/06/07
  61. * @since JDK1.1
  62. */
  63. public class ObjectStreamClass_1_3_1 implements java.io.Serializable {
  64. public static final long kDefaultUID = -1;
  65. private static Object noArgsList[] = {};
  66. private static Class noTypesList[] = {};
  67. private static Hashtable translatedFields;
  68. /** Find the descriptor for a class that can be serialized. Null
  69. * is returned if the specified class does not implement
  70. * java.io.Serializable or java.io.Externalizable.
  71. */
  72. static final ObjectStreamClass_1_3_1 lookup(Class cl)
  73. {
  74. ObjectStreamClass_1_3_1 desc = lookupInternal(cl);
  75. if (desc.isSerializable() || desc.isExternalizable())
  76. return desc;
  77. return null;
  78. }
  79. /*
  80. * Find the class descriptor for the specified class.
  81. * Package access only so it can be called from ObjectIn/OutStream.
  82. */
  83. static ObjectStreamClass_1_3_1 lookupInternal(Class cl)
  84. {
  85. /* Synchronize on the hashtable so no two threads will do
  86. * this at the same time.
  87. */
  88. ObjectStreamClass_1_3_1 desc = null;
  89. synchronized (descriptorFor) {
  90. /* Find the matching descriptor if it already known */
  91. desc = findDescriptorFor(cl);
  92. if (desc != null) {
  93. return desc;
  94. }
  95. /* Check if it's serializable */
  96. boolean serializable = classSerializable.isAssignableFrom(cl);
  97. /* If the class is only Serializable,
  98. * lookup the descriptor for the superclass.
  99. */
  100. ObjectStreamClass_1_3_1 superdesc = null;
  101. if (serializable) {
  102. Class superclass = cl.getSuperclass();
  103. if (superclass != null)
  104. superdesc = lookup(superclass);
  105. }
  106. /* Check if its' externalizable.
  107. * If it's Externalizable, clear the serializable flag.
  108. * Only one or the other may be set in the protocol.
  109. */
  110. boolean externalizable = false;
  111. if (serializable) {
  112. externalizable =
  113. ((superdesc != null) && superdesc.isExternalizable()) ||
  114. classExternalizable.isAssignableFrom(cl);
  115. if (externalizable) {
  116. serializable = false;
  117. }
  118. }
  119. /* Create a new version descriptor,
  120. * it put itself in the known table.
  121. */
  122. desc = new ObjectStreamClass_1_3_1(cl, superdesc,
  123. serializable, externalizable);
  124. }
  125. desc.init();
  126. return desc;
  127. }
  128. /**
  129. * The name of the class described by this descriptor.
  130. */
  131. public final String getName() {
  132. return name;
  133. }
  134. /**
  135. * Return the serialVersionUID for this class.
  136. * The serialVersionUID defines a set of classes all with the same name
  137. * that have evolved from a common root class and agree to be serialized
  138. * and deserialized using a common format.
  139. */
  140. public static final long getSerialVersionUID( java.lang.Class clazz) {
  141. ObjectStreamClass_1_3_1 theosc = ObjectStreamClass_1_3_1.lookup( clazz );
  142. if( theosc != null )
  143. {
  144. return theosc.getSerialVersionUID( );
  145. }
  146. return 0;
  147. }
  148. /**
  149. * Return the serialVersionUID for this class.
  150. * The serialVersionUID defines a set of classes all with the same name
  151. * that have evolved from a common root class and agree to be serialized
  152. * and deserialized using a common format.
  153. */
  154. public final long getSerialVersionUID() {
  155. return suid;
  156. }
  157. /**
  158. * Return the serialVersionUID string for this class.
  159. * The serialVersionUID defines a set of classes all with the same name
  160. * that have evolved from a common root class and agree to be serialized
  161. * and deserialized using a common format.
  162. */
  163. public final String getSerialVersionUIDStr() {
  164. if (suidStr == null)
  165. suidStr = Long.toHexString(suid).toUpperCase();
  166. return suidStr;
  167. }
  168. /**
  169. * Return the actual (computed) serialVersionUID for this class.
  170. */
  171. public static final long getActualSerialVersionUID( java.lang.Class clazz )
  172. {
  173. ObjectStreamClass_1_3_1 theosc = ObjectStreamClass_1_3_1.lookup( clazz );
  174. if( theosc != null )
  175. {
  176. return theosc.getActualSerialVersionUID( );
  177. }
  178. return 0;
  179. }
  180. /**
  181. * Return the actual (computed) serialVersionUID for this class.
  182. */
  183. public final long getActualSerialVersionUID() {
  184. return actualSuid;
  185. }
  186. /**
  187. * Return the actual (computed) serialVersionUID for this class.
  188. */
  189. public final String getActualSerialVersionUIDStr() {
  190. if (actualSuidStr == null)
  191. actualSuidStr = Long.toHexString(actualSuid).toUpperCase();
  192. return actualSuidStr;
  193. }
  194. /**
  195. * Return the class in the local VM that this version is mapped to.
  196. * Null is returned if there is no corresponding local class.
  197. */
  198. public final Class forClass() {
  199. return ofClass;
  200. }
  201. /**
  202. * Return an array of the fields of this serializable class.
  203. * @return an array containing an element for each persistent
  204. * field of this class. Returns an array of length zero if
  205. * there are no fields.
  206. * @since JDK1.2
  207. */
  208. public ObjectStreamField[] getFields() {
  209. // Return a copy so the caller can't change the fields.
  210. if (fields.length > 0) {
  211. ObjectStreamField[] dup = new ObjectStreamField[fields.length];
  212. System.arraycopy(fields, 0, dup, 0, fields.length);
  213. return dup;
  214. } else {
  215. return fields;
  216. }
  217. }
  218. public boolean hasField(ValueMember field){
  219. for (int i = 0; i < fields.length; i++){
  220. try{
  221. if (fields[i].getName().equals(field.name)) {
  222. if (fields[i].getSignature().equals(ValueUtility.getSignature(field)))
  223. return true;
  224. }
  225. }
  226. catch(Throwable t){}
  227. }
  228. return false;
  229. }
  230. /* Avoid unnecessary allocations. */
  231. final ObjectStreamField[] getFieldsNoCopy() {
  232. return fields;
  233. }
  234. /**
  235. * Get the field of this class by name.
  236. * @return The ObjectStreamField object of the named field or null if there
  237. * is no such named field.
  238. */
  239. public final ObjectStreamField getField(String name) {
  240. /* Binary search of fields by name.
  241. */
  242. for (int i = fields.length-1; i >= 0; i--) {
  243. if (name.equals(fields[i].getName())) {
  244. return fields[i];
  245. }
  246. }
  247. return null;
  248. }
  249. public Serializable writeReplace(Serializable value) {
  250. if (writeReplaceObjectMethod != null) {
  251. try {
  252. return (Serializable) writeReplaceObjectMethod.invoke(value,noArgsList);
  253. }
  254. catch(Throwable t) {
  255. throw new RuntimeException(t.getMessage());
  256. }
  257. }
  258. else return value;
  259. }
  260. public Object readResolve(Object value) {
  261. if (readResolveObjectMethod != null) {
  262. try {
  263. return readResolveObjectMethod.invoke(value,noArgsList);
  264. }
  265. catch(Throwable t) {
  266. throw new RuntimeException(t.getMessage());
  267. }
  268. }
  269. else return value;
  270. }
  271. /**
  272. * Return a string describing this ObjectStreamClass_1_3_1.
  273. */
  274. public final String toString() {
  275. StringBuffer sb = new StringBuffer();
  276. sb.append(name);
  277. sb.append(": static final long serialVersionUID = ");
  278. sb.append(Long.toString(suid));
  279. sb.append("L;");
  280. return sb.toString();
  281. }
  282. /*
  283. * Create a new ObjectStreamClass_1_3_1 from a loaded class.
  284. * Don't call this directly, call lookup instead.
  285. */
  286. private ObjectStreamClass_1_3_1(java.lang.Class cl, ObjectStreamClass_1_3_1 superdesc,
  287. boolean serial, boolean extern)
  288. {
  289. ofClass = cl; /* created from this class */
  290. if (Proxy.isProxyClass(cl)) {
  291. forProxyClass = true;
  292. }
  293. name = cl.getName();
  294. superclass = superdesc;
  295. serializable = serial;
  296. if (!forProxyClass) {
  297. // proxy classes are never externalizable
  298. externalizable = extern;
  299. }
  300. /*
  301. * Enter this class in the table of known descriptors.
  302. * Otherwise, when the fields are read it may recurse
  303. * trying to find the descriptor for itself.
  304. */
  305. insertDescriptorFor(this);
  306. /*
  307. * The remainder of initialization occurs in init(), which is called
  308. * after the lock on the global class descriptor table has been
  309. * released.
  310. */
  311. }
  312. /*
  313. * Initialize class descriptor. This method is only invoked on class
  314. * descriptors created via calls to lookupInternal(). This method is kept
  315. * separate from the ObjectStreamClass_1_3_1 constructor so that lookupInternal
  316. * does not have to hold onto a global class descriptor table lock while the
  317. * class descriptor is being initialized (see bug 4165204).
  318. */
  319. private void init() {
  320. synchronized (lock) {
  321. final Class cl = ofClass;
  322. if (fields != null) // already initialized
  323. return;
  324. if (!serializable ||
  325. externalizable ||
  326. forProxyClass ||
  327. name.equals("java.lang.String")) {
  328. fields = NO_FIELDS;
  329. } else if (serializable) {
  330. /* Ask for permission to override field access checks.
  331. */
  332. AccessController.doPrivileged(new PrivilegedAction() {
  333. public Object run() {
  334. /* Fill in the list of persistent fields.
  335. * If it is declared, use the declared serialPersistentFields.
  336. * Otherwise, extract the fields from the class itself.
  337. */
  338. try {
  339. Field pf = cl.getDeclaredField("serialPersistentFields");
  340. // serial bug 7; the serialPersistentFields were not
  341. // being read and stored as Accessible bit was not set
  342. pf.setAccessible(true);
  343. // serial bug 7; need to find if the field is of type
  344. // java.io.ObjectStreamField
  345. java.io.ObjectStreamField[] f =
  346. (java.io.ObjectStreamField[])pf.get(cl);
  347. int mods = pf.getModifiers();
  348. if ((Modifier.isPrivate(mods)) &&
  349. (Modifier.isStatic(mods)) &&
  350. (Modifier.isFinal(mods)))
  351. {
  352. fields = (ObjectStreamField[])translateFields((Object[])pf.get(cl));
  353. }
  354. } catch (NoSuchFieldException e) {
  355. fields = null;
  356. } catch (IllegalAccessException e) {
  357. fields = null;
  358. } catch (IllegalArgumentException e) {
  359. fields = null;
  360. } catch (ClassCastException e) {
  361. /* Thrown if a field serialPersistentField exists
  362. * but it is not of type ObjectStreamField.
  363. */
  364. fields = null;
  365. }
  366. if (fields == null) {
  367. /* Get all of the declared fields for this
  368. * Class. setAccessible on all fields so they
  369. * can be accessed later. Create a temporary
  370. * ObjectStreamField array to hold each
  371. * non-static, non-transient field. Then copy the
  372. * temporary array into an array of the correct
  373. * size once the number of fields is known.
  374. */
  375. Field[] actualfields = cl.getDeclaredFields();
  376. int numFields = 0;
  377. ObjectStreamField[] tempFields =
  378. new ObjectStreamField[actualfields.length];
  379. for (int i = 0; i < actualfields.length; i++) {
  380. int modifiers = actualfields[i].getModifiers();
  381. if (!Modifier.isStatic(modifiers) &&
  382. !Modifier.isTransient(modifiers)) {
  383. tempFields[numFields++] =
  384. new ObjectStreamField(actualfields[i]);
  385. }
  386. }
  387. fields = new ObjectStreamField[numFields];
  388. System.arraycopy(tempFields, 0, fields, 0, numFields);
  389. } else {
  390. // For each declared persistent field, look for an actual
  391. // reflected Field. If there is one, make sure it's the correct
  392. // type and cache it in the ObjectStreamClass_1_3_1 for that field.
  393. for (int j = fields.length-1; j >= 0; j--) {
  394. try {
  395. Field reflField = cl.getDeclaredField(fields[j].getName());
  396. if (fields[j].getType() == reflField.getType()) {
  397. // reflField.setAccessible(true);
  398. fields[j].setField(reflField);
  399. }
  400. } catch (NoSuchFieldException e) {
  401. // Nothing to do
  402. }
  403. }
  404. }
  405. return null;
  406. }
  407. });
  408. if (fields.length > 1)
  409. Arrays.sort(fields);
  410. /* Set up field data for use while writing using the API api. */
  411. computeFieldInfo();
  412. }
  413. /* Get the serialVersionUID from the class.
  414. * It uses the access override mechanism so make sure
  415. * the field objects is only used here.
  416. *
  417. * NonSerializable classes have a serialVerisonUID of 0L.
  418. */
  419. if (isNonSerializable()) {
  420. suid = 0L;
  421. } else {
  422. // Lookup special Serializable members using reflection.
  423. AccessController.doPrivileged(new PrivilegedAction() {
  424. public Object run() {
  425. if (forProxyClass) {
  426. // proxy classes always have serialVersionUID of 0L
  427. suid = 0L;
  428. } else {
  429. try {
  430. final Field f = cl.getDeclaredField("serialVersionUID");
  431. int mods = f.getModifiers();
  432. // SerialBug 5: static final SUID should be read
  433. if (Modifier.isStatic(mods) &&
  434. Modifier.isFinal(mods) ) {
  435. f.setAccessible(true);
  436. suid = f.getLong(cl);
  437. // get rid of native code
  438. // suid = getSerialVersionUIDField(cl);
  439. // SerialBug 2: should be computed after writeObject
  440. // actualSuid = computeStructuralUID(cl);
  441. } else {
  442. suid = ObjectStreamClass.getSerialVersionUID(cl);
  443. // SerialBug 2: should be computed after writeObject
  444. // actualSuid = computeStructuralUID(cl);
  445. }
  446. } catch (NoSuchFieldException ex) {
  447. suid = ObjectStreamClass.getSerialVersionUID(cl);
  448. // SerialBug 2: should be computed after writeObject
  449. // actualSuid = computeStructuralUID(cl);
  450. } catch (IllegalAccessException ex) {
  451. suid = ObjectStreamClass.getSerialVersionUID(cl);
  452. }
  453. }
  454. try {
  455. writeReplaceObjectMethod = cl.getDeclaredMethod("writeReplace", noTypesList);
  456. if (Modifier.isStatic(writeReplaceObjectMethod.getModifiers())) {
  457. writeReplaceObjectMethod = null;
  458. } else {
  459. writeReplaceObjectMethod.setAccessible(true);
  460. }
  461. } catch (NoSuchMethodException e2) {
  462. }
  463. try {
  464. readResolveObjectMethod = cl.getDeclaredMethod("readResolve", noTypesList);
  465. if (Modifier.isStatic(readResolveObjectMethod.getModifiers())) {
  466. readResolveObjectMethod = null;
  467. } else {
  468. readResolveObjectMethod.setAccessible(true);
  469. }
  470. } catch (NoSuchMethodException e2) {
  471. }
  472. /* Cache lookup of writeObject and readObject for
  473. * Serializable classes. (Do not lookup for
  474. * Externalizable)
  475. */
  476. if (serializable && !forProxyClass) {
  477. /* Look for the writeObject method
  478. * Set the accessible flag on it here. ObjectOutputStream
  479. * will call it as necessary.
  480. */
  481. try {
  482. Class[] args = {java.io.ObjectOutputStream.class};
  483. writeObjectMethod = cl.getDeclaredMethod("writeObject", args);
  484. hasWriteObjectMethod = true;
  485. int mods = writeObjectMethod.getModifiers();
  486. // Method must be private and non-static
  487. if (!Modifier.isPrivate(mods) ||
  488. Modifier.isStatic(mods)) {
  489. writeObjectMethod = null;
  490. hasWriteObjectMethod = false;
  491. }
  492. } catch (NoSuchMethodException e) {
  493. }
  494. /* Look for the readObject method
  495. * set the access override and save the reference for
  496. * ObjectInputStream so it can all the method directly.
  497. */
  498. try {
  499. Class[] args = {java.io.ObjectInputStream.class};
  500. readObjectMethod = cl.getDeclaredMethod("readObject", args);
  501. int mods = readObjectMethod.getModifiers();
  502. // Method must be private and non-static
  503. if (!Modifier.isPrivate(mods) ||
  504. Modifier.isStatic(mods)) {
  505. readObjectMethod = null;
  506. }
  507. } catch (NoSuchMethodException e) {
  508. }
  509. // Compute the structural UID. This must be done after the
  510. // calculation for writeObject. Fixed 4/20/2000, eea1
  511. // SerialBug 2: to have correct value in RepId
  512. }
  513. return null;
  514. }
  515. });
  516. }
  517. actualSuid = computeStructuralUID(this, cl);
  518. }
  519. }
  520. /*
  521. * Create an empty ObjectStreamClass_1_3_1 for a class about to be read.
  522. * This is separate from read so ObjectInputStream can assign the
  523. * wire handle early, before any nested ObjectStreamClass_1_3_1 might
  524. * be read.
  525. */
  526. ObjectStreamClass_1_3_1(String n, long s) {
  527. name = n;
  528. suid = s;
  529. superclass = null;
  530. }
  531. private static Object[] translateFields(Object objs[])
  532. throws NoSuchFieldException {
  533. try{
  534. java.io.ObjectStreamField fields[] = (java.io.ObjectStreamField[])objs;
  535. Object translation[] = null;
  536. if (translatedFields == null)
  537. translatedFields = new Hashtable();
  538. translation = (Object[])translatedFields.get(fields);
  539. if (translation != null)
  540. return translation;
  541. else {
  542. Class osfClass = com.sun.corba.se.impl.orbutil.ObjectStreamField.class;
  543. translation = (Object[])java.lang.reflect.Array.newInstance(osfClass, objs.length);
  544. Object arg[] = new Object[2];
  545. Class types[] = {String.class, Class.class};
  546. Constructor constructor = osfClass.getDeclaredConstructor(types);
  547. for (int i = fields.length -1; i >= 0; i--){
  548. arg[0] = fields[i].getName();
  549. arg[1] = fields[i].getType();
  550. translation[i] = constructor.newInstance(arg);
  551. }
  552. translatedFields.put(fields, translation);
  553. }
  554. return (Object[])translation;
  555. }
  556. catch(Throwable t){
  557. throw new NoSuchFieldException();
  558. }
  559. }
  560. /* Compare the base class names of streamName and localName.
  561. *
  562. * @return Return true iff the base class name compare.
  563. * @parameter streamName Fully qualified class name.
  564. * @parameter localName Fully qualified class name.
  565. * @parameter pkgSeparator class names use either '.' or '/'.
  566. *
  567. * Only compare base class name to allow package renaming.
  568. */
  569. static boolean compareClassNames(String streamName,
  570. String localName,
  571. char pkgSeparator) {
  572. /* compare the class names, stripping off package names. */
  573. int streamNameIndex = streamName.lastIndexOf(pkgSeparator);
  574. if (streamNameIndex < 0)
  575. streamNameIndex = 0;
  576. int localNameIndex = localName.lastIndexOf(pkgSeparator);
  577. if (localNameIndex < 0)
  578. localNameIndex = 0;
  579. return streamName.regionMatches(false, streamNameIndex,
  580. localName, localNameIndex,
  581. streamName.length() - streamNameIndex);
  582. }
  583. /*
  584. * Compare the types of two class descriptors.
  585. * They match if they have the same class name and suid
  586. */
  587. final boolean typeEquals(ObjectStreamClass_1_3_1 other) {
  588. return (suid == other.suid) &&
  589. compareClassNames(name, other.name, '.');
  590. }
  591. /*
  592. * Return the superclass descriptor of this descriptor.
  593. */
  594. final void setSuperclass(ObjectStreamClass_1_3_1 s) {
  595. superclass = s;
  596. }
  597. /*
  598. * Return the superclass descriptor of this descriptor.
  599. */
  600. final ObjectStreamClass_1_3_1 getSuperclass() {
  601. return superclass;
  602. }
  603. /*
  604. * Return whether the class has a writeObject method
  605. */
  606. final boolean hasWriteObject() {
  607. return hasWriteObjectMethod;
  608. }
  609. final boolean isCustomMarshaled() {
  610. return (hasWriteObject() || isExternalizable());
  611. }
  612. /*
  613. * Return true if all instances of 'this' Externalizable class
  614. * are written in block-data mode from the stream that 'this' was read
  615. * from. <p>
  616. *
  617. * In JDK 1.1, all Externalizable instances are not written
  618. * in block-data mode.
  619. * In JDK 1.2, all Externalizable instances, by default, are written
  620. * in block-data mode and the Externalizable instance is terminated with
  621. * tag TC_ENDBLOCKDATA. Change enabled the ability to skip Externalizable
  622. * instances.
  623. *
  624. * IMPLEMENTATION NOTE:
  625. * This should have been a mode maintained per stream; however,
  626. * for compatibility reasons, it was only possible to record
  627. * this change per class. All Externalizable classes within
  628. * a given stream should either have this mode enabled or
  629. * disabled. This is enforced by not allowing the PROTOCOL_VERSION
  630. * of a stream to he changed after any objects have been written.
  631. *
  632. * @see ObjectOutputStream#useProtocolVersion
  633. * @see ObjectStreamConstants#PROTOCOL_VERSION_1
  634. * @see ObjectStreamConstants#PROTOCOL_VERSION_2
  635. *
  636. * @since JDK 1.2
  637. */
  638. boolean hasExternalizableBlockDataMode() {
  639. return hasExternalizableBlockData;
  640. }
  641. /*
  642. * Return the ObjectStreamClass_1_3_1 of the local class this one is based on.
  643. */
  644. final ObjectStreamClass_1_3_1 localClassDescriptor() {
  645. return localClassDesc;
  646. }
  647. /*
  648. * Get the Serializability of the class.
  649. */
  650. boolean isSerializable() {
  651. return serializable;
  652. }
  653. /*
  654. * Get the externalizability of the class.
  655. */
  656. boolean isExternalizable() {
  657. return externalizable;
  658. }
  659. boolean isNonSerializable() {
  660. return ! (externalizable || serializable);
  661. }
  662. /*
  663. * Calculate the size of the array needed to store primitive data and the
  664. * number of object references to read when reading from the input
  665. * stream.
  666. */
  667. private void computeFieldInfo() {
  668. primBytes = 0;
  669. objFields = 0;
  670. for (int i = 0; i < fields.length; i++ ) {
  671. switch (fields[i].getTypeCode()) {
  672. case 'B':
  673. case 'Z':
  674. primBytes += 1;
  675. break;
  676. case 'C':
  677. case 'S':
  678. primBytes += 2;
  679. break;
  680. case 'I':
  681. case 'F':
  682. primBytes += 4;
  683. break;
  684. case 'J':
  685. case 'D' :
  686. primBytes += 8;
  687. break;
  688. case 'L':
  689. case '[':
  690. objFields += 1;
  691. break;
  692. }
  693. }
  694. }
  695. private static long computeStructuralUID(ObjectStreamClass_1_3_1 osc, Class cl) {
  696. ByteArrayOutputStream devnull = new ByteArrayOutputStream(512);
  697. long h = 0;
  698. try {
  699. if ((!java.io.Serializable.class.isAssignableFrom(cl)) ||
  700. (cl.isInterface())){
  701. return 0;
  702. }
  703. if (java.io.Externalizable.class.isAssignableFrom(cl)) {
  704. return 1;
  705. }
  706. MessageDigest md = MessageDigest.getInstance("SHA");
  707. DigestOutputStream mdo = new DigestOutputStream(devnull, md);
  708. DataOutputStream data = new DataOutputStream(mdo);
  709. // Get SUID of parent
  710. Class parent = cl.getSuperclass();
  711. if ((parent != null))
  712. // SerialBug 1; acc. to spec the one for
  713. // java.lang.object
  714. // should be computed and put
  715. // && (parent != java.lang.Object.class))
  716. {
  717. //data.writeLong(computeSerialVersionUID(null,parent));
  718. data.writeLong(computeStructuralUID(lookup(parent), parent));
  719. }
  720. if (osc.hasWriteObject())
  721. data.writeInt(2);
  722. else
  723. data.writeInt(1);
  724. /* Sort the field names to get a deterministic order */
  725. // Field[] field = ObjectStreamClass_1_3_1.getDeclaredFields(cl);
  726. ObjectStreamField[] fields = osc.getFields();
  727. // Must make sure that the Field array we allocate
  728. // below is exactly the right size. Bug fix for
  729. // 4397133.
  730. int numNonNullFields = 0;
  731. for (int i = 0; i < fields.length; i++)
  732. if (fields[i].getField() != null)
  733. numNonNullFields++;
  734. Field [] field = new java.lang.reflect.Field[numNonNullFields];
  735. for (int i = 0, fieldNum = 0; i < fields.length; i++) {
  736. if (fields[i].getField() != null) {
  737. field[fieldNum++] = fields[i].getField();
  738. }
  739. }
  740. if (field.length > 1)
  741. Arrays.sort(field, compareMemberByName);
  742. for (int i = 0; i < field.length; i++) {
  743. Field f = field[i];
  744. /* Include in the hash all fields except those that are
  745. * transient
  746. */
  747. int m = f.getModifiers();
  748. //Serial 6
  749. //if (Modifier.isTransient(m) || Modifier.isStatic(m))
  750. // spec reference 00-01-06.pdf, 1.3.5.6, states non-static
  751. // non-transient, public fields are mapped to Java IDL.
  752. //
  753. // Here's the quote from the first paragraph:
  754. // Java non-static non-transient public fields are mapped to
  755. // OMG IDL public data members, and other Java fields are
  756. // not mapped.
  757. // if (Modifier.isTransient(m) || Modifier.isStatic(m))
  758. // continue;
  759. data.writeUTF(f.getName());
  760. data.writeUTF(getSignature(f.getType()));
  761. }
  762. /* Compute the hash value for this class.
  763. * Use only the first 64 bits of the hash.
  764. */
  765. data.flush();
  766. byte hasharray[] = md.digest();
  767. // int minimum = Math.min(8, hasharray.length);
  768. // SerialBug 3: SHA computation is wrong; for loop reversed
  769. //for (int i = minimum; i > 0; i--)
  770. for (int i = 0; i < Math.min(8, hasharray.length); i++) {
  771. h += (long)(hasharray[i] & 255) << (i * 8);
  772. }
  773. } catch (IOException ignore) {
  774. /* can't happen, but be deterministic anyway. */
  775. h = -1;
  776. } catch (NoSuchAlgorithmException complain) {
  777. throw new SecurityException(complain.getMessage());
  778. }
  779. return h;
  780. }
  781. /**
  782. * Compute the JVM signature for the class.
  783. */
  784. static String getSignature(Class clazz) {
  785. String type = null;
  786. if (clazz.isArray()) {
  787. Class cl = clazz;
  788. int dimensions = 0;
  789. while (cl.isArray()) {
  790. dimensions++;
  791. cl = cl.getComponentType();
  792. }
  793. StringBuffer sb = new StringBuffer();
  794. for (int i = 0; i < dimensions; i++) {
  795. sb.append("[");
  796. }
  797. sb.append(getSignature(cl));
  798. type = sb.toString();
  799. } else if (clazz.isPrimitive()) {
  800. if (clazz == Integer.TYPE) {
  801. type = "I";
  802. } else if (clazz == Byte.TYPE) {
  803. type = "B";
  804. } else if (clazz == Long.TYPE) {
  805. type = "J";
  806. } else if (clazz == Float.TYPE) {
  807. type = "F";
  808. } else if (clazz == Double.TYPE) {
  809. type = "D";
  810. } else if (clazz == Short.TYPE) {
  811. type = "S";
  812. } else if (clazz == Character.TYPE) {
  813. type = "C";
  814. } else if (clazz == Boolean.TYPE) {
  815. type = "Z";
  816. } else if (clazz == Void.TYPE) {
  817. type = "V";
  818. }
  819. } else {
  820. type = "L" + clazz.getName().replace('.', '/') + ";";
  821. }
  822. return type;
  823. }
  824. /*
  825. * Compute the JVM method descriptor for the method.
  826. */
  827. static String getSignature(Method meth) {
  828. StringBuffer sb = new StringBuffer();
  829. sb.append("(");
  830. Class[] params = meth.getParameterTypes(); // avoid clone
  831. for (int j = 0; j < params.length; j++) {
  832. sb.append(getSignature(params[j]));
  833. }
  834. sb.append(")");
  835. sb.append(getSignature(meth.getReturnType()));
  836. return sb.toString();
  837. }
  838. /*
  839. * Compute the JVM constructor descriptor for the constructor.
  840. */
  841. static String getSignature(Constructor cons) {
  842. StringBuffer sb = new StringBuffer();
  843. sb.append("(");
  844. Class[] params = cons.getParameterTypes(); // avoid clone
  845. for (int j = 0; j < params.length; j++) {
  846. sb.append(getSignature(params[j]));
  847. }
  848. sb.append(")V");
  849. return sb.toString();
  850. }
  851. /*
  852. * Cache of Class -> ClassDescriptor Mappings.
  853. */
  854. static private ObjectStreamClassEntry[] descriptorFor = new ObjectStreamClassEntry[61];
  855. /*
  856. * findDescriptorFor a Class. This looks in the cache for a
  857. * mapping from Class -> ObjectStreamClass mappings. The hashCode
  858. * of the Class is used for the lookup since the Class is the key.
  859. * The entries are extended from java.lang.ref.SoftReference so the
  860. * gc will be able to free them if needed.
  861. */
  862. private static ObjectStreamClass_1_3_1 findDescriptorFor(Class cl) {
  863. int hash = cl.hashCode();
  864. int index = (hash & 0x7FFFFFFF) % descriptorFor.length;
  865. ObjectStreamClassEntry e;
  866. ObjectStreamClassEntry prev;
  867. /* Free any initial entries whose refs have been cleared */
  868. while ((e = descriptorFor[index]) != null && e.get() == null) {
  869. descriptorFor[index] = e.next;
  870. }
  871. /* Traverse the chain looking for a descriptor with ofClass == cl.
  872. * unlink entries that are unresolved.
  873. */
  874. prev = e;
  875. while (e != null ) {
  876. ObjectStreamClass_1_3_1 desc = (ObjectStreamClass_1_3_1)(e.get());
  877. if (desc == null) {
  878. // This entry has been cleared, unlink it
  879. prev.next = e.next;
  880. } else {
  881. if (desc.ofClass == cl)
  882. return desc;
  883. prev = e;
  884. }
  885. e = e.next;
  886. }
  887. return null;
  888. }
  889. /*
  890. * insertDescriptorFor a Class -> ObjectStreamClass_1_3_1 mapping.
  891. */
  892. private static void insertDescriptorFor(ObjectStreamClass_1_3_1 desc) {
  893. // Make sure not already present
  894. if (findDescriptorFor(desc.ofClass) != null) {
  895. return;
  896. }
  897. int hash = desc.ofClass.hashCode();
  898. int index = (hash & 0x7FFFFFFF) % descriptorFor.length;
  899. ObjectStreamClassEntry e = new ObjectStreamClassEntry(desc);
  900. e.next = descriptorFor[index];
  901. descriptorFor[index] = e;
  902. }
  903. private static Field[] getDeclaredFields(final Class clz) {
  904. return (Field[]) AccessController.doPrivileged(new PrivilegedAction() {
  905. public Object run() {
  906. return clz.getDeclaredFields();
  907. }
  908. });
  909. }
  910. /*
  911. * The name of this descriptor
  912. */
  913. private String name;
  914. /*
  915. * The descriptor of the supertype.
  916. */
  917. private ObjectStreamClass_1_3_1 superclass;
  918. /*
  919. * Flags for Serializable and Externalizable.
  920. */
  921. private boolean serializable;
  922. private boolean externalizable;
  923. /*
  924. * Array of persistent fields of this class, sorted by
  925. * type and name.
  926. */
  927. private ObjectStreamField[] fields;
  928. /*
  929. * Class that is a descriptor for in this virtual machine.
  930. */
  931. private Class ofClass;
  932. /*
  933. * True if descriptor for a proxy class.
  934. */
  935. boolean forProxyClass;
  936. /*
  937. * SerialVersionUID for this class.
  938. */
  939. private long suid = kDefaultUID;
  940. private String suidStr = null;
  941. /*
  942. * Actual (computed) SerialVersionUID for this class.
  943. */
  944. private long actualSuid = kDefaultUID;
  945. private String actualSuidStr = null;
  946. /*
  947. * The total number of bytes of primitive fields.
  948. * The total number of object fields.
  949. */
  950. int primBytes;
  951. int objFields;
  952. /* Internal lock object. */
  953. private Object lock = new Object();
  954. /* True if this class has/had a writeObject method */
  955. private boolean hasWriteObjectMethod;
  956. /* In JDK 1.1, external data was not written in block mode.
  957. * As of JDK 1.2, external data is written in block data mode. This
  958. * flag enables JDK 1.2 to be able to read JDK 1.1 written external data.
  959. *
  960. * @since JDK 1.2
  961. */
  962. private boolean hasExternalizableBlockData;
  963. Method writeObjectMethod;
  964. Method readObjectMethod;
  965. private Method writeReplaceObjectMethod;
  966. private Method readResolveObjectMethod;
  967. /*
  968. * ObjectStreamClass_1_3_1 that this one was built from.
  969. */
  970. private ObjectStreamClass_1_3_1 localClassDesc;
  971. /* Get the private static final field for serial version UID */
  972. // private static native long getSerialVersionUIDField(Class cl);
  973. /* The Class Object for java.io.Serializable */
  974. private static Class classSerializable = null;
  975. private static Class classExternalizable = null;
  976. /*
  977. * Resolve java.io.Serializable at load time.
  978. */
  979. static {
  980. try {
  981. classSerializable = Class.forName("java.io.Serializable");
  982. classExternalizable = Class.forName("java.io.Externalizable");
  983. } catch (Throwable e) {
  984. System.err.println("Could not load java.io.Serializable or java.io.Externalizable.");
  985. }
  986. }
  987. /** use serialVersionUID from JDK 1.1. for interoperability */
  988. private static final long serialVersionUID = -6120832682080437368L;
  989. /**
  990. * Set serialPersistentFields of a Serializable class to this value to
  991. * denote that the class has no Serializable fields.
  992. */
  993. public static final ObjectStreamField[] NO_FIELDS =
  994. new ObjectStreamField[0];
  995. /*
  996. * Entries held in the Cache of known ObjectStreamClass_1_3_1 objects.
  997. * Entries are chained together with the same hash value (modulo array size).
  998. */
  999. private static class ObjectStreamClassEntry // extends java.lang.ref.SoftReference
  1000. {
  1001. ObjectStreamClassEntry(ObjectStreamClass_1_3_1 c) {
  1002. //super(c);
  1003. this.c = c;
  1004. }
  1005. ObjectStreamClassEntry next;
  1006. public Object get()
  1007. {
  1008. return c;
  1009. }
  1010. private ObjectStreamClass_1_3_1 c;
  1011. }
  1012. /*
  1013. * Comparator object for Classes and Interfaces
  1014. */
  1015. private static Comparator compareClassByName =
  1016. new CompareClassByName();
  1017. private static class CompareClassByName implements Comparator {
  1018. public int compare(Object o1, Object o2) {
  1019. Class c1 = (Class)o1;
  1020. Class c2 = (Class)o2;
  1021. return (c1.getName()).compareTo(c2.getName());
  1022. }
  1023. }
  1024. /*
  1025. * Comparator object for Members, Fields, and Methods
  1026. */
  1027. private static Comparator compareMemberByName =
  1028. new CompareMemberByName();
  1029. private static class CompareMemberByName implements Comparator {
  1030. public int compare(Object o1, Object o2) {
  1031. String s1 = ((Member)o1).getName();
  1032. String s2 = ((Member)o2).getName();
  1033. if (o1 instanceof Method) {
  1034. s1 += getSignature((Method)o1);
  1035. s2 += getSignature((Method)o2);
  1036. } else if (o1 instanceof Constructor) {
  1037. s1 += getSignature((Constructor)o1);
  1038. s2 += getSignature((Constructor)o2);
  1039. }
  1040. return s1.compareTo(s2);
  1041. }
  1042. }
  1043. /* It is expensive to recompute a method or constructor signature
  1044. many times, so compute it only once using this data structure. */
  1045. private static class MethodSignature implements Comparator {
  1046. Member member;
  1047. String signature; // cached parameter signature
  1048. /* Given an array of Method or Constructor members,
  1049. return a sorted array of the non-private members.*/
  1050. /* A better implementation would be to implement the returned data
  1051. structure as an insertion sorted link list.*/
  1052. static MethodSignature[] removePrivateAndSort(Member[] m) {
  1053. int numNonPrivate = 0;
  1054. for (int i = 0; i < m.length; i++) {
  1055. if (! Modifier.isPrivate(m[i].getModifiers())) {
  1056. numNonPrivate++;
  1057. }
  1058. }
  1059. MethodSignature[] cm = new MethodSignature[numNonPrivate];
  1060. int cmi = 0;
  1061. for (int i = 0; i < m.length; i++) {
  1062. if (! Modifier.isPrivate(m[i].getModifiers())) {
  1063. cm[cmi] = new MethodSignature(m[i]);
  1064. cmi++;
  1065. }
  1066. }
  1067. if (cmi > 0)
  1068. Arrays.sort(cm, cm[0]);
  1069. return cm;
  1070. }
  1071. /* Assumes that o1 and o2 are either both methods
  1072. or both constructors.*/
  1073. public int compare(Object o1, Object o2) {
  1074. /* Arrays.sort calls compare when o1 and o2 are equal.*/
  1075. if (o1 == o2)
  1076. return 0;
  1077. MethodSignature c1 = (MethodSignature)o1;
  1078. MethodSignature c2 = (MethodSignature)o2;
  1079. int result;
  1080. if (isConstructor()) {
  1081. result = c1.signature.compareTo(c2.signature);
  1082. } else { // is a Method.
  1083. result = c1.member.getName().compareTo(c2.member.getName());
  1084. if (result == 0)
  1085. result = c1.signature.compareTo(c2.signature);
  1086. }
  1087. return result;
  1088. }
  1089. final private boolean isConstructor() {
  1090. return member instanceof Constructor;
  1091. }
  1092. private MethodSignature(Member m) {
  1093. member = m;
  1094. if (isConstructor()) {
  1095. signature = ObjectStreamClass_1_3_1.getSignature((Constructor)m);
  1096. } else {
  1097. signature = ObjectStreamClass_1_3_1.getSignature((Method)m);
  1098. }
  1099. }
  1100. }
  1101. }