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