1. /*
  2. * @(#)ObjectStreamClass.java 1.53 04/07/16
  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.io;
  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 com.sun.corba.se.impl.util.RepositoryId;
  40. import org.omg.CORBA.ValueMember;
  41. import sun.corba.Bridge;
  42. /**
  43. * A ObjectStreamClass describes a class that can be serialized to a stream
  44. * or a class that was serialized to a stream. It contains the name
  45. * and the serialVersionUID of the class.
  46. * <br>
  47. * The ObjectStreamClass for a specific class loaded in this Java VM can
  48. * be found using the lookup method.
  49. *
  50. * @author Roger Riggs
  51. * @(#)ObjectStreamClass.java 1.17 99/06/07
  52. * @since JDK1.1
  53. */
  54. public class ObjectStreamClass implements java.io.Serializable {
  55. private static final boolean DEBUG_SVUID = false ;
  56. public static final long kDefaultUID = -1;
  57. private static Object noArgsList[] = {};
  58. private static Class noTypesList[] = {};
  59. private static Hashtable translatedFields;
  60. private static final Bridge bridge =
  61. (Bridge)AccessController.doPrivileged(
  62. new PrivilegedAction() {
  63. public Object run() {
  64. return Bridge.get() ;
  65. }
  66. }
  67. ) ;
  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 lookup(Class cl)
  73. {
  74. ObjectStreamClass 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 lookupInternal(Class cl)
  84. {
  85. /* Synchronize on the hashtable so no two threads will do
  86. * this at the same time.
  87. */
  88. ObjectStreamClass desc = null;
  89. synchronized (descriptorFor) {
  90. /* Find the matching descriptor if it already known */
  91. desc = findDescriptorFor(cl);
  92. if (desc == null) {
  93. /* Check if it's serializable */
  94. boolean serializable = classSerializable.isAssignableFrom(cl);
  95. /* If the class is only Serializable,
  96. * lookup the descriptor for the superclass.
  97. */
  98. ObjectStreamClass superdesc = null;
  99. if (serializable) {
  100. Class superclass = cl.getSuperclass();
  101. if (superclass != null)
  102. superdesc = lookup(superclass);
  103. }
  104. /* Check if its' externalizable.
  105. * If it's Externalizable, clear the serializable flag.
  106. * Only one or the other may be set in the protocol.
  107. */
  108. boolean externalizable = false;
  109. if (serializable) {
  110. externalizable =
  111. ((superdesc != null) && superdesc.isExternalizable()) ||
  112. classExternalizable.isAssignableFrom(cl);
  113. if (externalizable) {
  114. serializable = false;
  115. }
  116. }
  117. /* Create a new version descriptor,
  118. * it put itself in the known table.
  119. */
  120. desc = new ObjectStreamClass(cl, superdesc,
  121. serializable, externalizable);
  122. }
  123. }
  124. // Must always call init. See bug 4488137. This code was
  125. // incorrectly changed to return immediately on a non-null
  126. // cache result. That allowed threads to gain access to
  127. // unintialized instances.
  128. //
  129. // All threads must sync on the member variable lock
  130. // and check the initialization state.
  131. //
  132. // Another possibility is to continue to synchronize on the
  133. // descriptorFor array, but that leads to poor performance
  134. // (see bug 4165204 "ObjectStreamClass can hold global lock
  135. // for a very long time").
  136. desc.init();
  137. return desc;
  138. }
  139. /**
  140. * The name of the class described by this descriptor.
  141. */
  142. public final String getName() {
  143. return name;
  144. }
  145. /**
  146. * Return the serialVersionUID for this class.
  147. * The serialVersionUID defines a set of classes all with the same name
  148. * that have evolved from a common root class and agree to be serialized
  149. * and deserialized using a common format.
  150. */
  151. public static final long getSerialVersionUID( java.lang.Class clazz) {
  152. ObjectStreamClass theosc = ObjectStreamClass.lookup( clazz );
  153. if( theosc != null )
  154. {
  155. return theosc.getSerialVersionUID( );
  156. }
  157. return 0;
  158. }
  159. /**
  160. * Return the serialVersionUID for this class.
  161. * The serialVersionUID defines a set of classes all with the same name
  162. * that have evolved from a common root class and agree to be serialized
  163. * and deserialized using a common format.
  164. */
  165. public final long getSerialVersionUID() {
  166. return suid;
  167. }
  168. /**
  169. * Return the serialVersionUID string for this class.
  170. * The serialVersionUID defines a set of classes all with the same name
  171. * that have evolved from a common root class and agree to be serialized
  172. * and deserialized using a common format.
  173. */
  174. public final String getSerialVersionUIDStr() {
  175. if (suidStr == null)
  176. suidStr = Long.toHexString(suid).toUpperCase();
  177. return suidStr;
  178. }
  179. /**
  180. * Return the actual (computed) serialVersionUID for this class.
  181. */
  182. public static final long getActualSerialVersionUID( java.lang.Class clazz )
  183. {
  184. ObjectStreamClass theosc = ObjectStreamClass.lookup( clazz );
  185. if( theosc != null )
  186. {
  187. return theosc.getActualSerialVersionUID( );
  188. }
  189. return 0;
  190. }
  191. /**
  192. * Return the actual (computed) serialVersionUID for this class.
  193. */
  194. public final long getActualSerialVersionUID() {
  195. return actualSuid;
  196. }
  197. /**
  198. * Return the actual (computed) serialVersionUID for this class.
  199. */
  200. public final String getActualSerialVersionUIDStr() {
  201. if (actualSuidStr == null)
  202. actualSuidStr = Long.toHexString(actualSuid).toUpperCase();
  203. return actualSuidStr;
  204. }
  205. /**
  206. * Return the class in the local VM that this version is mapped to.
  207. * Null is returned if there is no corresponding local class.
  208. */
  209. public final Class forClass() {
  210. return ofClass;
  211. }
  212. /**
  213. * Return an array of the fields of this serializable class.
  214. * @return an array containing an element for each persistent
  215. * field of this class. Returns an array of length zero if
  216. * there are no fields.
  217. * @since JDK1.2
  218. */
  219. public ObjectStreamField[] getFields() {
  220. // Return a copy so the caller can't change the fields.
  221. if (fields.length > 0) {
  222. ObjectStreamField[] dup = new ObjectStreamField[fields.length];
  223. System.arraycopy(fields, 0, dup, 0, fields.length);
  224. return dup;
  225. } else {
  226. return fields;
  227. }
  228. }
  229. public boolean hasField(ValueMember field)
  230. {
  231. try {
  232. for (int i = 0; i < fields.length; i++) {
  233. if (fields[i].getName().equals(field.name)) {
  234. if (fields[i].getSignature().equals(
  235. ValueUtility.getSignature(field)))
  236. return true;
  237. }
  238. }
  239. } catch (Exception exc) {
  240. // Ignore this; all we want to do is return false
  241. // Note that ValueUtility.getSignature can throw checked exceptions.
  242. }
  243. return false;
  244. }
  245. /* Avoid unnecessary allocations. */
  246. final ObjectStreamField[] getFieldsNoCopy() {
  247. return fields;
  248. }
  249. /**
  250. * Get the field of this class by name.
  251. * @return The ObjectStreamField object of the named field or null if there
  252. * is no such named field.
  253. */
  254. public final ObjectStreamField getField(String name) {
  255. /* Binary search of fields by name.
  256. */
  257. for (int i = fields.length-1; i >= 0; i--) {
  258. if (name.equals(fields[i].getName())) {
  259. return fields[i];
  260. }
  261. }
  262. return null;
  263. }
  264. public Serializable writeReplace(Serializable value) {
  265. if (writeReplaceObjectMethod != null) {
  266. try {
  267. return (Serializable) writeReplaceObjectMethod.invoke(value,noArgsList);
  268. } catch(Throwable t) {
  269. throw new RuntimeException(t);
  270. }
  271. }
  272. else return value;
  273. }
  274. public Object readResolve(Object value) {
  275. if (readResolveObjectMethod != null) {
  276. try {
  277. return readResolveObjectMethod.invoke(value,noArgsList);
  278. } catch(Throwable t) {
  279. throw new RuntimeException(t);
  280. }
  281. }
  282. else return value;
  283. }
  284. /**
  285. * Return a string describing this ObjectStreamClass.
  286. */
  287. public final String toString() {
  288. StringBuffer sb = new StringBuffer();
  289. sb.append(name);
  290. sb.append(": static final long serialVersionUID = ");
  291. sb.append(Long.toString(suid));
  292. sb.append("L;");
  293. return sb.toString();
  294. }
  295. /*
  296. * Create a new ObjectStreamClass from a loaded class.
  297. * Don't call this directly, call lookup instead.
  298. */
  299. private ObjectStreamClass(java.lang.Class cl, ObjectStreamClass superdesc,
  300. boolean serial, boolean extern)
  301. {
  302. ofClass = cl; /* created from this class */
  303. if (Proxy.isProxyClass(cl)) {
  304. forProxyClass = true;
  305. }
  306. name = cl.getName();
  307. superclass = superdesc;
  308. serializable = serial;
  309. if (!forProxyClass) {
  310. // proxy classes are never externalizable
  311. externalizable = extern;
  312. }
  313. /*
  314. * Enter this class in the table of known descriptors.
  315. * Otherwise, when the fields are read it may recurse
  316. * trying to find the descriptor for itself.
  317. */
  318. insertDescriptorFor(this);
  319. /*
  320. * The remainder of initialization occurs in init(), which is called
  321. * after the lock on the global class descriptor table has been
  322. * released.
  323. */
  324. }
  325. /*
  326. * Initialize class descriptor. This method is only invoked on class
  327. * descriptors created via calls to lookupInternal(). This method is kept
  328. * separate from the ObjectStreamClass constructor so that lookupInternal
  329. * does not have to hold onto a global class descriptor table lock while the
  330. * class descriptor is being initialized (see bug 4165204).
  331. */
  332. private void init() {
  333. synchronized (lock) {
  334. // See description at definition of initialized.
  335. if (initialized)
  336. return;
  337. final Class cl = ofClass;
  338. if (!serializable ||
  339. externalizable ||
  340. forProxyClass ||
  341. name.equals("java.lang.String")) {
  342. fields = NO_FIELDS;
  343. } else if (serializable) {
  344. /* Ask for permission to override field access checks.
  345. */
  346. AccessController.doPrivileged(new PrivilegedAction() {
  347. public Object run() {
  348. /* Fill in the list of persistent fields.
  349. * If it is declared, use the declared serialPersistentFields.
  350. * Otherwise, extract the fields from the class itself.
  351. */
  352. try {
  353. Field pf = cl.getDeclaredField("serialPersistentFields");
  354. // serial bug 7; the serialPersistentFields were not
  355. // being read and stored as Accessible bit was not set
  356. pf.setAccessible(true);
  357. // serial bug 7; need to find if the field is of type
  358. // java.io.ObjectStreamField
  359. java.io.ObjectStreamField[] f =
  360. (java.io.ObjectStreamField[])pf.get(cl);
  361. int mods = pf.getModifiers();
  362. if ((Modifier.isPrivate(mods)) &&
  363. (Modifier.isStatic(mods)) &&
  364. (Modifier.isFinal(mods)))
  365. {
  366. fields = (ObjectStreamField[])translateFields((Object[])pf.get(cl));
  367. }
  368. } catch (NoSuchFieldException e) {
  369. fields = null;
  370. } catch (IllegalAccessException e) {
  371. fields = null;
  372. } catch (IllegalArgumentException e) {
  373. fields = null;
  374. } catch (ClassCastException e) {
  375. /* Thrown if a field serialPersistentField exists
  376. * but it is not of type ObjectStreamField.
  377. */
  378. fields = null;
  379. }
  380. if (fields == null) {
  381. /* Get all of the declared fields for this
  382. * Class. setAccessible on all fields so they
  383. * can be accessed later. Create a temporary
  384. * ObjectStreamField array to hold each
  385. * non-static, non-transient field. Then copy the
  386. * temporary array into an array of the correct
  387. * size once the number of fields is known.
  388. */
  389. Field[] actualfields = cl.getDeclaredFields();
  390. int numFields = 0;
  391. ObjectStreamField[] tempFields =
  392. new ObjectStreamField[actualfields.length];
  393. for (int i = 0; i < actualfields.length; i++) {
  394. Field fld = actualfields[i] ;
  395. int modifiers = fld.getModifiers();
  396. if (!Modifier.isStatic(modifiers) &&
  397. !Modifier.isTransient(modifiers)) {
  398. fld.setAccessible(true) ;
  399. tempFields[numFields++] = new ObjectStreamField(fld);
  400. }
  401. }
  402. fields = new ObjectStreamField[numFields];
  403. System.arraycopy(tempFields, 0, fields, 0, numFields);
  404. } else {
  405. // For each declared persistent field, look for an actual
  406. // reflected Field. If there is one, make sure it's the correct
  407. // type and cache it in the ObjectStreamClass for that field.
  408. for (int j = fields.length-1; j >= 0; j--) {
  409. try {
  410. Field reflField = cl.getDeclaredField(fields[j].getName());
  411. if (fields[j].getType() == reflField.getType()) {
  412. reflField.setAccessible(true);
  413. fields[j].setField(reflField);
  414. }
  415. } catch (NoSuchFieldException e) {
  416. // Nothing to do
  417. }
  418. }
  419. }
  420. return null;
  421. }
  422. });
  423. if (fields.length > 1)
  424. Arrays.sort(fields);
  425. /* Set up field data for use while writing using the API api. */
  426. computeFieldInfo();
  427. }
  428. /* Get the serialVersionUID from the class.
  429. * It uses the access override mechanism so make sure
  430. * the field objects is only used here.
  431. *
  432. * NonSerializable classes have a serialVerisonUID of 0L.
  433. */
  434. if (isNonSerializable()) {
  435. suid = 0L;
  436. } else {
  437. // Lookup special Serializable members using reflection.
  438. AccessController.doPrivileged(new PrivilegedAction() {
  439. public Object run() {
  440. if (forProxyClass) {
  441. // proxy classes always have serialVersionUID of 0L
  442. suid = 0L;
  443. } else {
  444. try {
  445. final Field f = cl.getDeclaredField("serialVersionUID");
  446. int mods = f.getModifiers();
  447. // SerialBug 5: static final SUID should be read
  448. if (Modifier.isStatic(mods) && Modifier.isFinal(mods) ) {
  449. f.setAccessible(true);
  450. suid = f.getLong(cl);
  451. // SerialBug 2: should be computed after writeObject
  452. // actualSuid = computeStructuralUID(cl);
  453. } else {
  454. suid = _computeSerialVersionUID(cl);
  455. // SerialBug 2: should be computed after writeObject
  456. // actualSuid = computeStructuralUID(cl);
  457. }
  458. } catch (NoSuchFieldException ex) {
  459. suid = _computeSerialVersionUID(cl);
  460. // SerialBug 2: should be computed after writeObject
  461. // actualSuid = computeStructuralUID(cl);
  462. } catch (IllegalAccessException ex) {
  463. suid = _computeSerialVersionUID(cl);
  464. }
  465. }
  466. writeReplaceObjectMethod = ObjectStreamClass.getInheritableMethod(cl,
  467. "writeReplace", noTypesList, Object.class);
  468. readResolveObjectMethod = ObjectStreamClass.getInheritableMethod(cl,
  469. "readResolve", noTypesList, Object.class);
  470. if (externalizable)
  471. cons = getExternalizableConstructor(cl) ;
  472. else
  473. cons = getSerializableConstructor(cl) ;
  474. if (serializable && !forProxyClass) {
  475. /* Look for the writeObject method
  476. * Set the accessible flag on it here. ObjectOutputStream
  477. * will call it as necessary.
  478. */
  479. writeObjectMethod = getPrivateMethod( cl, "writeObject",
  480. new Class[] { java.io.ObjectOutputStream.class }, Void.TYPE ) ;
  481. readObjectMethod = getPrivateMethod( cl, "readObject",
  482. new Class[] { java.io.ObjectInputStream.class }, Void.TYPE ) ;
  483. }
  484. return null;
  485. }
  486. });
  487. }
  488. // This call depends on a lot of information computed above!
  489. actualSuid = ObjectStreamClass.computeStructuralUID(this, cl);
  490. // If we have a write object method, precompute the
  491. // RMI-IIOP stream format version 2 optional data
  492. // repository ID.
  493. if (hasWriteObject())
  494. rmiiiopOptionalDataRepId = computeRMIIIOPOptionalDataRepId();
  495. // This must be done last.
  496. initialized = true;
  497. }
  498. }
  499. /**
  500. * Returns non-static private method with given signature defined by given
  501. * class, or null if none found. Access checks are disabled on the
  502. * returned method (if any).
  503. */
  504. private static Method getPrivateMethod(Class cl, String name,
  505. Class[] argTypes,
  506. Class returnType)
  507. {
  508. try {
  509. Method meth = cl.getDeclaredMethod(name, argTypes);
  510. meth.setAccessible(true);
  511. int mods = meth.getModifiers();
  512. return ((meth.getReturnType() == returnType) &&
  513. ((mods & Modifier.STATIC) == 0) &&
  514. ((mods & Modifier.PRIVATE) != 0)) ? meth : null;
  515. } catch (NoSuchMethodException ex) {
  516. return null;
  517. }
  518. }
  519. // Specific to RMI-IIOP
  520. /**
  521. * Java to IDL ptc-02-01-12 1.5.1
  522. *
  523. * "The rep_id string passed to the start_value method must be
  524. * 'RMI:org.omg.custom.class:hashcode:suid' where class is the
  525. * fully-qualified name of the class whose writeObject method
  526. * is being invoked and hashcode and suid are the class's hashcode
  527. * and SUID."
  528. */
  529. private String computeRMIIIOPOptionalDataRepId() {
  530. StringBuffer sbuf = new StringBuffer("RMI:org.omg.custom.");
  531. sbuf.append(RepositoryId.convertToISOLatin1(this.getName()));
  532. sbuf.append(':');
  533. sbuf.append(this.getActualSerialVersionUIDStr());
  534. sbuf.append(':');
  535. sbuf.append(this.getSerialVersionUIDStr());
  536. return sbuf.toString();
  537. }
  538. /**
  539. * This will return null if there is no writeObject method.
  540. */
  541. public final String getRMIIIOPOptionalDataRepId() {
  542. return rmiiiopOptionalDataRepId;
  543. }
  544. /*
  545. * Create an empty ObjectStreamClass for a class about to be read.
  546. * This is separate from read so ObjectInputStream can assign the
  547. * wire handle early, before any nested ObjectStreamClass might
  548. * be read.
  549. */
  550. ObjectStreamClass(String n, long s) {
  551. name = n;
  552. suid = s;
  553. superclass = null;
  554. }
  555. private static Object[] translateFields(Object objs[])
  556. throws NoSuchFieldException {
  557. try{
  558. java.io.ObjectStreamField fields[] = (java.io.ObjectStreamField[])objs;
  559. Object translation[] = null;
  560. if (translatedFields == null)
  561. translatedFields = new Hashtable();
  562. translation = (Object[])translatedFields.get(fields);
  563. if (translation != null)
  564. return translation;
  565. else {
  566. Class osfClass = Class.forName("com.sun.corba.se.impl.io.ObjectStreamField");
  567. translation = (Object[])java.lang.reflect.Array.newInstance(osfClass, objs.length);
  568. Object arg[] = new Object[2];
  569. Class types[] = {String.class, Class.class};
  570. Constructor constructor = osfClass.getDeclaredConstructor(types);
  571. for (int i = fields.length -1; i >= 0; i--){
  572. arg[0] = fields[i].getName();
  573. arg[1] = fields[i].getType();
  574. translation[i] = constructor.newInstance(arg);
  575. }
  576. translatedFields.put(fields, translation);
  577. }
  578. return (Object[])translation;
  579. }
  580. catch(Throwable t){
  581. NoSuchFieldException nsfe = new NoSuchFieldException();
  582. nsfe.initCause( t ) ;
  583. throw nsfe ;
  584. }
  585. }
  586. /*
  587. * Set the class this version descriptor matches.
  588. * The base class name and serializable hash must match.
  589. * Fill in the reflected Fields that will be used
  590. * for reading.
  591. */
  592. final void setClass(Class cl) throws InvalidClassException {
  593. if (cl == null) {
  594. localClassDesc = null;
  595. ofClass = null;
  596. computeFieldInfo();
  597. return;
  598. }
  599. localClassDesc = lookupInternal(cl);
  600. if (localClassDesc == null)
  601. // XXX I18N, logging needed
  602. throw new InvalidClassException(cl.getName(),
  603. "Local class not compatible");
  604. if (suid != localClassDesc.suid) {
  605. /* Check for exceptional cases that allow mismatched suid. */
  606. /* Allow adding Serializable or Externalizable
  607. * to a later release of the class.
  608. */
  609. boolean addedSerialOrExtern =
  610. isNonSerializable() || localClassDesc.isNonSerializable();
  611. /* Disregard the serialVersionUID of an array
  612. * when name and cl.Name differ. If resolveClass() returns
  613. * an array with a different package name,
  614. * the serialVersionUIDs will not match since the fully
  615. * qualified array class is used in the
  616. * computation of the array's serialVersionUID. There is
  617. * no way to set a permanent serialVersionUID for an array type.
  618. */
  619. boolean arraySUID = (cl.isArray() && ! cl.getName().equals(name));
  620. if (! arraySUID && ! addedSerialOrExtern ) {
  621. // XXX I18N, logging needed
  622. throw new InvalidClassException(cl.getName(),
  623. "Local class not compatible:" +
  624. " stream classdesc serialVersionUID=" + suid +
  625. " local class serialVersionUID=" + localClassDesc.suid);
  626. }
  627. }
  628. /* compare the class names, stripping off package names. */
  629. if (! compareClassNames(name, cl.getName(), '.'))
  630. // XXX I18N, logging needed
  631. throw new InvalidClassException(cl.getName(),
  632. "Incompatible local class name. " +
  633. "Expected class name compatible with " +
  634. name);
  635. /*
  636. * Test that both implement either serializable or externalizable.
  637. */
  638. // The next check is more generic, since it covers the
  639. // Proxy case, the JDK 1.3 serialization code has
  640. // both checks
  641. //if ((serializable && localClassDesc.externalizable) ||
  642. // (externalizable && localClassDesc.serializable))
  643. // throw new InvalidClassException(localCl.getName(),
  644. // "Serializable is incompatible with Externalizable");
  645. if ((serializable != localClassDesc.serializable) ||
  646. (externalizable != localClassDesc.externalizable) ||
  647. (!serializable && !externalizable))
  648. // XXX I18N, logging needed
  649. throw new InvalidClassException(cl.getName(),
  650. "Serialization incompatible with Externalization");
  651. /* Set up the reflected Fields in the class where the value of each
  652. * field in this descriptor should be stored.
  653. * Each field in this ObjectStreamClass (the source) is located (by
  654. * name) in the ObjectStreamClass of the class(the destination).
  655. * In the usual (non-versioned case) the field is in both
  656. * descriptors and the types match, so the reflected Field is copied.
  657. * If the type does not match, a InvalidClass exception is thrown.
  658. * If the field is not present in the class, the reflected Field
  659. * remains null so the field will be read but discarded.
  660. * If extra fields are present in the class they are ignored. Their
  661. * values will be set to the default value by the object allocator.
  662. * Both the src and dest field list are sorted by type and name.
  663. */
  664. ObjectStreamField[] destfield =
  665. (ObjectStreamField[])localClassDesc.fields;
  666. ObjectStreamField[] srcfield =
  667. (ObjectStreamField[])fields;
  668. int j = 0;
  669. nextsrc:
  670. for (int i = 0; i < srcfield.length; i++ ) {
  671. /* Find this field in the dest*/
  672. for (int k = j; k < destfield.length; k++) {
  673. if (srcfield[i].getName().equals(destfield[k].getName())) {
  674. /* found match */
  675. if (srcfield[i].isPrimitive() &&
  676. !srcfield[i].typeEquals(destfield[k])) {
  677. // XXX I18N, logging needed
  678. throw new InvalidClassException(cl.getName(),
  679. "The type of field " +
  680. srcfield[i].getName() +
  681. " of class " + name +
  682. " is incompatible.");
  683. }
  684. /* Skip over any fields in the dest that are not in the src */
  685. j = k;
  686. srcfield[i].setField(destfield[j].getField());
  687. // go on to the next source field
  688. continue nextsrc;
  689. }
  690. }
  691. }
  692. /* Set up field data for use while reading from the input stream. */
  693. computeFieldInfo();
  694. /* Remember the class this represents */
  695. ofClass = cl;
  696. /* get the cache of these methods from the local class
  697. * implementation.
  698. */
  699. readObjectMethod = localClassDesc.readObjectMethod;
  700. readResolveObjectMethod = localClassDesc.readResolveObjectMethod;
  701. }
  702. /* Compare the base class names of streamName and localName.
  703. *
  704. * @return Return true iff the base class name compare.
  705. * @parameter streamName Fully qualified class name.
  706. * @parameter localName Fully qualified class name.
  707. * @parameter pkgSeparator class names use either '.' or '/'.
  708. *
  709. * Only compare base class name to allow package renaming.
  710. */
  711. static boolean compareClassNames(String streamName,
  712. String localName,
  713. char pkgSeparator) {
  714. /* compare the class names, stripping off package names. */
  715. int streamNameIndex = streamName.lastIndexOf(pkgSeparator);
  716. if (streamNameIndex < 0)
  717. streamNameIndex = 0;
  718. int localNameIndex = localName.lastIndexOf(pkgSeparator);
  719. if (localNameIndex < 0)
  720. localNameIndex = 0;
  721. return streamName.regionMatches(false, streamNameIndex,
  722. localName, localNameIndex,
  723. streamName.length() - streamNameIndex);
  724. }
  725. /*
  726. * Compare the types of two class descriptors.
  727. * They match if they have the same class name and suid
  728. */
  729. final boolean typeEquals(ObjectStreamClass other) {
  730. return (suid == other.suid) &&
  731. compareClassNames(name, other.name, '.');
  732. }
  733. /*
  734. * Return the superclass descriptor of this descriptor.
  735. */
  736. final void setSuperclass(ObjectStreamClass s) {
  737. superclass = s;
  738. }
  739. /*
  740. * Return the superclass descriptor of this descriptor.
  741. */
  742. final ObjectStreamClass getSuperclass() {
  743. return superclass;
  744. }
  745. /**
  746. * Return whether the class has a readObject method
  747. */
  748. final boolean hasReadObject() {
  749. return readObjectMethod != null;
  750. }
  751. /*
  752. * Return whether the class has a writeObject method
  753. */
  754. final boolean hasWriteObject() {
  755. return writeObjectMethod != null ;
  756. }
  757. /**
  758. * Returns when or not this class should be custom
  759. * marshaled (use chunking). This should happen if
  760. * it is Externalizable OR if it or
  761. * any of its superclasses has a writeObject method,
  762. */
  763. final boolean isCustomMarshaled() {
  764. return (hasWriteObject() || isExternalizable())
  765. || (superclass != null && superclass.isCustomMarshaled());
  766. }
  767. /*
  768. * Return true if all instances of 'this' Externalizable class
  769. * are written in block-data mode from the stream that 'this' was read
  770. * from. <p>
  771. *
  772. * In JDK 1.1, all Externalizable instances are not written
  773. * in block-data mode.
  774. * In JDK 1.2, all Externalizable instances, by default, are written
  775. * in block-data mode and the Externalizable instance is terminated with
  776. * tag TC_ENDBLOCKDATA. Change enabled the ability to skip Externalizable
  777. * instances.
  778. *
  779. * IMPLEMENTATION NOTE:
  780. * This should have been a mode maintained per stream; however,
  781. * for compatibility reasons, it was only possible to record
  782. * this change per class. All Externalizable classes within
  783. * a given stream should either have this mode enabled or
  784. * disabled. This is enforced by not allowing the PROTOCOL_VERSION
  785. * of a stream to he changed after any objects have been written.
  786. *
  787. * @see ObjectOutputStream#useProtocolVersion
  788. * @see ObjectStreamConstants#PROTOCOL_VERSION_1
  789. * @see ObjectStreamConstants#PROTOCOL_VERSION_2
  790. *
  791. * @since JDK 1.2
  792. */
  793. boolean hasExternalizableBlockDataMode() {
  794. return hasExternalizableBlockData;
  795. }
  796. /**
  797. * Creates a new instance of the represented class. If the class is
  798. * externalizable, invokes its public no-arg constructor; otherwise, if the
  799. * class is serializable, invokes the no-arg constructor of the first
  800. * non-serializable superclass. Throws UnsupportedOperationException if
  801. * this class descriptor is not associated with a class, if the associated
  802. * class is non-serializable or if the appropriate no-arg constructor is
  803. * inaccessible/unavailable.
  804. */
  805. Object newInstance()
  806. throws InstantiationException, InvocationTargetException,
  807. UnsupportedOperationException
  808. {
  809. if (cons != null) {
  810. try {
  811. return cons.newInstance(new Object[0]);
  812. } catch (IllegalAccessException ex) {
  813. // should not occur, as access checks have been suppressed
  814. InternalError ie = new InternalError();
  815. ie.initCause( ex ) ;
  816. throw ie ;
  817. }
  818. } else {
  819. throw new UnsupportedOperationException();
  820. }
  821. }
  822. /**
  823. * Returns public no-arg constructor of given class, or null if none found.
  824. * Access checks are disabled on the returned constructor (if any), since
  825. * the defining class may still be non-public.
  826. */
  827. private static Constructor getExternalizableConstructor(Class cl) {
  828. try {
  829. Constructor cons = cl.getDeclaredConstructor(new Class[0]);
  830. cons.setAccessible(true);
  831. return ((cons.getModifiers() & Modifier.PUBLIC) != 0) ?
  832. cons : null;
  833. } catch (NoSuchMethodException ex) {
  834. return null;
  835. }
  836. }
  837. /**
  838. * Returns subclass-accessible no-arg constructor of first non-serializable
  839. * superclass, or null if none found. Access checks are disabled on the
  840. * returned constructor (if any).
  841. */
  842. private static Constructor getSerializableConstructor(Class cl) {
  843. Class initCl = cl;
  844. while (Serializable.class.isAssignableFrom(initCl)) {
  845. if ((initCl = initCl.getSuperclass()) == null) {
  846. return null;
  847. }
  848. }
  849. try {
  850. Constructor cons = initCl.getDeclaredConstructor(new Class[0]);
  851. int mods = cons.getModifiers();
  852. if ((mods & Modifier.PRIVATE) != 0 ||
  853. ((mods & (Modifier.PUBLIC | Modifier.PROTECTED)) == 0 &&
  854. !packageEquals(cl, initCl)))
  855. {
  856. return null;
  857. }
  858. cons = bridge.newConstructorForSerialization(cl, cons);
  859. cons.setAccessible(true);
  860. return cons;
  861. } catch (NoSuchMethodException ex) {
  862. return null;
  863. }
  864. }
  865. /*
  866. * Return the ObjectStreamClass of the local class this one is based on.
  867. */
  868. final ObjectStreamClass localClassDescriptor() {
  869. return localClassDesc;
  870. }
  871. /*
  872. * Get the Serializability of the class.
  873. */
  874. boolean isSerializable() {
  875. return serializable;
  876. }
  877. /*
  878. * Get the externalizability of the class.
  879. */
  880. boolean isExternalizable() {
  881. return externalizable;
  882. }
  883. boolean isNonSerializable() {
  884. return ! (externalizable || serializable);
  885. }
  886. /*
  887. * Calculate the size of the array needed to store primitive data and the
  888. * number of object references to read when reading from the input
  889. * stream.
  890. */
  891. private void computeFieldInfo() {
  892. primBytes = 0;
  893. objFields = 0;
  894. for (int i = 0; i < fields.length; i++ ) {
  895. switch (fields[i].getTypeCode()) {
  896. case 'B':
  897. case 'Z':
  898. primBytes += 1;
  899. break;
  900. case 'C':
  901. case 'S':
  902. primBytes += 2;
  903. break;
  904. case 'I':
  905. case 'F':
  906. primBytes += 4;
  907. break;
  908. case 'J':
  909. case 'D' :
  910. primBytes += 8;
  911. break;
  912. case 'L':
  913. case '[':
  914. objFields += 1;
  915. break;
  916. }
  917. }
  918. }
  919. private static void msg( String str )
  920. {
  921. System.out.println( str ) ;
  922. }
  923. /* JDK 1.5 has introduced some new modifier bits (such as SYNTHETIC)
  924. * that can affect the SVUID computation (see bug 4897937). These bits
  925. * must be ignored, as otherwise interoperability with ORBs in earlier
  926. * JDK versions can be compromised. I am adding these masks for this
  927. * purpose as discussed in the CCC for this bug (see http://ccc.sfbay/4897937).
  928. */
  929. public static final int CLASS_MASK = Modifier.PUBLIC | Modifier.FINAL |
  930. Modifier.INTERFACE | Modifier.ABSTRACT ;
  931. public static final int FIELD_MASK = Modifier.PUBLIC | Modifier.PRIVATE |
  932. Modifier.PROTECTED | Modifier.STATIC | Modifier.FINAL |
  933. Modifier.TRANSIENT | Modifier.VOLATILE ;
  934. public static final int METHOD_MASK = Modifier.PUBLIC | Modifier.PRIVATE |
  935. Modifier.PROTECTED | Modifier.STATIC | Modifier.FINAL |
  936. Modifier.SYNCHRONIZED | Modifier.NATIVE | Modifier.ABSTRACT |
  937. Modifier.STRICT ;
  938. /*
  939. * Compute a hash for the specified class. Incrementally add
  940. * items to the hash accumulating in the digest stream.
  941. * Fold the hash into a long. Use the SHA secure hash function.
  942. */
  943. private static long _computeSerialVersionUID(Class cl) {
  944. if (DEBUG_SVUID)
  945. msg( "Computing SerialVersionUID for " + cl ) ;
  946. ByteArrayOutputStream devnull = new ByteArrayOutputStream(512);
  947. long h = 0;
  948. try {
  949. MessageDigest md = MessageDigest.getInstance("SHA");
  950. DigestOutputStream mdo = new DigestOutputStream(devnull, md);
  951. DataOutputStream data = new DataOutputStream(mdo);
  952. if (DEBUG_SVUID)
  953. msg( "\twriteUTF( \"" + cl.getName() + "\" )" ) ;
  954. data.writeUTF(cl.getName());
  955. int classaccess = cl.getModifiers();
  956. classaccess &= (Modifier.PUBLIC | Modifier.FINAL |
  957. Modifier.INTERFACE | Modifier.ABSTRACT);
  958. /* Workaround for javac bug that only set ABSTRACT for
  959. * interfaces if the interface had some methods.
  960. * The ABSTRACT bit reflects that the number of methods > 0.
  961. * This is required so correct hashes can be computed
  962. * for existing class files.
  963. * Previously this hack was previously present in the VM.
  964. */
  965. Method[] method = cl.getDeclaredMethods();
  966. if ((classaccess & Modifier.INTERFACE) != 0) {
  967. classaccess &= (~Modifier.ABSTRACT);
  968. if (method.length > 0) {
  969. classaccess |= Modifier.ABSTRACT;
  970. }
  971. }
  972. // Mask out any post-1.4 attributes
  973. classaccess &= CLASS_MASK ;
  974. if (DEBUG_SVUID)
  975. msg( "\twriteInt( " + classaccess + " ) " ) ;
  976. data.writeInt(classaccess);
  977. /*
  978. * Get the list of interfaces supported,
  979. * Accumulate their names their names in Lexical order
  980. * and add them to the hash
  981. */
  982. if (!cl.isArray()) {
  983. /* In 1.2fcs, getInterfaces() was modified to return
  984. * {java.lang.Cloneable, java.io.Serializable} when
  985. * called on array classes. These values would upset
  986. * the computation of the hash, so we explicitly omit
  987. * them from its computation.
  988. */
  989. Class interfaces[] = cl.getInterfaces();
  990. Arrays.sort(interfaces, compareClassByName);
  991. for (int i = 0; i < interfaces.length; i++) {
  992. if (DEBUG_SVUID)
  993. msg( "\twriteUTF( \"" + interfaces[i].getName() + "\" ) " ) ;
  994. data.writeUTF(interfaces[i].getName());
  995. }
  996. }
  997. /* Sort the field names to get a deterministic order */
  998. Field[] field = cl.getDeclaredFields();
  999. Arrays.sort(field, compareMemberByName);
  1000. for (int i = 0; i < field.length; i++) {
  1001. Field f = field[i];
  1002. /* Include in the hash all fields except those that are
  1003. * private transient and private static.
  1004. */
  1005. int m = f.getModifiers();
  1006. if (Modifier.isPrivate(m) &&
  1007. (Modifier.isTransient(m) || Modifier.isStatic(m)))
  1008. continue;
  1009. if (DEBUG_SVUID)
  1010. msg( "\twriteUTF( \"" + f.getName() + "\" ) " ) ;
  1011. data.writeUTF(f.getName());
  1012. // Mask out any post-1.4 bits
  1013. m &= FIELD_MASK ;
  1014. if (DEBUG_SVUID)
  1015. msg( "\twriteInt( " + m + " ) " ) ;
  1016. data.writeInt(m);
  1017. if (DEBUG_SVUID)
  1018. msg( "\twriteUTF( \"" + getSignature(f.getType()) + "\" ) " ) ;
  1019. data.writeUTF(getSignature(f.getType()));
  1020. }
  1021. if (hasStaticInitializer(cl)) {
  1022. if (DEBUG_SVUID)
  1023. msg( "\twriteUTF( \"<clinit>\" ) " ) ;
  1024. data.writeUTF("<clinit>");
  1025. if (DEBUG_SVUID)
  1026. msg( "\twriteInt( " + Modifier.STATIC + " )" ) ;
  1027. data.writeInt(Modifier.STATIC); // TBD: what modifiers does it have
  1028. if (DEBUG_SVUID)
  1029. msg( "\twriteUTF( \"()V\" )" ) ;
  1030. data.writeUTF("()V");
  1031. }
  1032. /*
  1033. * Get the list of constructors including name and signature
  1034. * Sort lexically, add all except the private constructors
  1035. * to the hash with their access flags
  1036. */
  1037. MethodSignature[] constructors =
  1038. MethodSignature.removePrivateAndSort(cl.getDeclaredConstructors());
  1039. for (int i = 0; i < constructors.length; i++) {
  1040. MethodSignature c = constructors[i];
  1041. String mname = "<init>";
  1042. String desc = c.signature;
  1043. desc = desc.replace('/', '.');
  1044. if (DEBUG_SVUID)
  1045. msg( "\twriteUTF( \"" + mname + "\" )" ) ;
  1046. data.writeUTF(mname);
  1047. // mask out post-1.4 modifiers
  1048. int modifier = c.member.getModifiers() & METHOD_MASK ;
  1049. if (DEBUG_SVUID)
  1050. msg( "\twriteInt( " + modifier + " ) " ) ;
  1051. data.writeInt( modifier ) ;
  1052. if (DEBUG_SVUID)
  1053. msg( "\twriteUTF( \"" + desc+ "\" )" ) ;
  1054. data.writeUTF(desc);
  1055. }
  1056. /* Include in the hash all methods except those that are
  1057. * private transient and private static.
  1058. */
  1059. MethodSignature[] methods =
  1060. MethodSignature.removePrivateAndSort(method);
  1061. for (int i = 0; i < methods.length; i++ ) {
  1062. MethodSignature m = methods[i];
  1063. String desc = m.signature;
  1064. desc = desc.replace('/', '.');
  1065. if (DEBUG_SVUID)
  1066. msg( "\twriteUTF( \"" + m.member.getName()+ "\" )" ) ;
  1067. data.writeUTF(m.member.getName());
  1068. // mask out post-1.4 modifiers
  1069. int modifier = m.member.getModifiers() & METHOD_MASK ;
  1070. if (DEBUG_SVUID)
  1071. msg( "\twriteInt( " + modifier + " ) " ) ;
  1072. data.writeInt( modifier ) ;
  1073. if (DEBUG_SVUID)
  1074. msg( "\twriteUTF( \"" + desc + "\" )" ) ;
  1075. data.writeUTF(desc);
  1076. }
  1077. /* Compute the hash value for this class.
  1078. * Use only the first 64 bits of the hash.
  1079. */
  1080. data.flush();
  1081. byte hasharray[] = md.digest();
  1082. for (int i = 0; i < Math.min(8, hasharray.length); i++) {
  1083. h += (long)(hasharray[i] & 255) << (i * 8);
  1084. }
  1085. } catch (IOException ignore) {
  1086. /* can't happen, but be deterministic anyway. */
  1087. h = -1;
  1088. } catch (NoSuchAlgorithmException complain) {
  1089. SecurityException se = new SecurityException() ;
  1090. se.initCause( complain ) ;
  1091. throw se ;
  1092. }
  1093. return h;
  1094. }
  1095. private static long computeStructuralUID(com.sun.corba.se.impl.io.ObjectStreamClass osc, Class cl) {
  1096. ByteArrayOutputStream devnull = new ByteArrayOutputStream(512);
  1097. long h = 0;
  1098. try {
  1099. if ((!java.io.Serializable.class.isAssignableFrom(cl)) ||
  1100. (cl.isInterface())){
  1101. return 0;
  1102. }
  1103. if (java.io.Externalizable.class.isAssignableFrom(cl)) {
  1104. return 1;
  1105. }
  1106. MessageDigest md = MessageDigest.getInstance("SHA");
  1107. DigestOutputStream mdo = new DigestOutputStream(devnull, md);
  1108. DataOutputStream data = new DataOutputStream(mdo);
  1109. // Get SUID of parent
  1110. Class parent = cl.getSuperclass();
  1111. if ((parent != null))
  1112. // SerialBug 1; acc. to spec the one for
  1113. // java.lang.object
  1114. // should be computed and put
  1115. // && (parent != java.lang.Object.class))
  1116. {
  1117. //data.writeLong(computeSerialVersionUID(null,parent));
  1118. data.writeLong(computeStructuralUID(lookup(parent), parent));
  1119. }
  1120. if (osc.hasWriteObject())
  1121. data.writeInt(2);
  1122. else
  1123. data.writeInt(1);
  1124. // CORBA formal 00-11-03 10.6.2: For each field of the
  1125. // class that is mapped to IDL, sorted lexicographically
  1126. // by Java field name, in increasing order...
  1127. ObjectStreamField[] field = osc.getFields();
  1128. if (field.length > 1) {
  1129. Arrays.sort(field, compareObjStrFieldsByName);
  1130. }
  1131. // ...Java field name in UTF encoding, field
  1132. // descriptor, as defined by the JVM spec...
  1133. for (int i = 0; i < field.length; i++) {
  1134. data.writeUTF(field[i].getName());
  1135. data.writeUTF(field[i].getSignature());
  1136. }
  1137. /* Compute the hash value for this class.
  1138. * Use only the first 64 bits of the hash.
  1139. */
  1140. data.flush();
  1141. byte hasharray[] = md.digest();
  1142. // int minimum = Math.min(8, hasharray.length);
  1143. // SerialBug 3: SHA computation is wrong; for loop reversed
  1144. //for (int i = minimum; i > 0; i--)
  1145. for (int i = 0; i < Math.min(8, hasharray.length); i++) {
  1146. h += (long)(hasharray[i] & 255) << (i * 8);
  1147. }
  1148. } catch (IOException ignore) {
  1149. /* can't happen, but be deterministic anyway. */
  1150. h = -1;
  1151. } catch (NoSuchAlgorithmException complain) {
  1152. SecurityException se = new SecurityException();
  1153. se.initCause( complain ) ;
  1154. throw se ;
  1155. }
  1156. return h;
  1157. }
  1158. /**
  1159. * Compute the JVM signature for the class.
  1160. */
  1161. static String getSignature(Class clazz) {
  1162. String type = null;
  1163. if (clazz.isArray()) {
  1164. Class cl = clazz;
  1165. int dimensions = 0;
  1166. while (cl.isArray()) {
  1167. dimensions++;
  1168. cl = cl.getComponentType();
  1169. }
  1170. StringBuffer sb = new StringBuffer();
  1171. for (int i = 0; i < dimensions; i++) {
  1172. sb.append("[");
  1173. }
  1174. sb.append(getSignature(cl));
  1175. type = sb.toString();
  1176. } else if (clazz.isPrimitive()) {
  1177. if (clazz == Integer.TYPE) {
  1178. type = "I";
  1179. } else if (clazz == Byte.TYPE) {
  1180. type = "B";
  1181. } else if (clazz == Long.TYPE) {
  1182. type = "J";
  1183. } else if (clazz == Float.TYPE) {
  1184. type = "F";
  1185. } else if (clazz == Double.TYPE) {
  1186. type = "D";
  1187. } else if (clazz == Short.TYPE) {
  1188. type = "S";
  1189. } else if (clazz == Character.TYPE) {
  1190. type = "C";
  1191. } else if (clazz == Boolean.TYPE) {
  1192. type = "Z";
  1193. } else if (clazz == Void.TYPE) {
  1194. type = "V";
  1195. }
  1196. } else {
  1197. type = "L" + clazz.getName().replace('.', '/') + ";";
  1198. }
  1199. return type;
  1200. }
  1201. /*
  1202. * Compute the JVM method descriptor for the method.
  1203. */
  1204. static String getSignature(Method meth) {
  1205. StringBuffer sb = new StringBuffer();
  1206. sb.append("(");
  1207. Class[] params = meth.getParameterTypes(); // avoid clone
  1208. for (int j = 0; j < params.length; j++) {
  1209. sb.append(getSignature(params[j]));
  1210. }
  1211. sb.append(")");
  1212. sb.append(getSignature(meth.getReturnType()));
  1213. return sb.toString();
  1214. }
  1215. /*
  1216. * Compute the JVM constructor descriptor for the constructor.
  1217. */
  1218. static String getSignature(Constructor cons) {
  1219. StringBuffer sb = new StringBuffer();
  1220. sb.append("(");
  1221. Class[] params = cons.getParameterTypes(); // avoid clone
  1222. for (int j = 0; j < params.length; j++) {
  1223. sb.append(getSignature(params[j]));
  1224. }
  1225. sb.append(")V");
  1226. return sb.toString();
  1227. }
  1228. /*
  1229. * Cache of Class -> ClassDescriptor Mappings.
  1230. */
  1231. static private ObjectStreamClassEntry[] descriptorFor = new ObjectStreamClassEntry[61];
  1232. /*
  1233. * findDescriptorFor a Class. This looks in the cache for a
  1234. * mapping from Class -> ObjectStreamClass mappings. The hashCode
  1235. * of the Class is used for the lookup since the Class is the key.
  1236. * The entries are extended from java.lang.ref.SoftReference so the
  1237. * gc will be able to free them if needed.
  1238. */
  1239. private static ObjectStreamClass findDescriptorFor(Class cl) {
  1240. int hash = cl.hashCode();
  1241. int index = (hash & 0x7FFFFFFF) % descriptorFor.length;
  1242. ObjectStreamClassEntry e;
  1243. ObjectStreamClassEntry prev;
  1244. /* Free any initial entries whose refs have been cleared */
  1245. while ((e = descriptorFor[index]) != null && e.get() == null) {
  1246. descriptorFor[index] = e.next;
  1247. }
  1248. /* Traverse the chain looking for a descriptor with ofClass == cl.
  1249. * unlink entries that are unresolved.
  1250. */
  1251. prev = e;
  1252. while (e != null ) {
  1253. ObjectStreamClass desc = (ObjectStreamClass)(e.get());
  1254. if (desc == null) {
  1255. // This entry has been cleared, unlink it
  1256. prev.next = e.next;
  1257. } else {
  1258. if (desc.ofClass == cl)
  1259. return desc;
  1260. prev = e;
  1261. }
  1262. e = e.next;
  1263. }
  1264. return null;
  1265. }
  1266. /*
  1267. * insertDescriptorFor a Class -> ObjectStreamClass mapping.
  1268. */
  1269. private static void insertDescriptorFor(ObjectStreamClass desc) {
  1270. // Make sure not already present
  1271. if (findDescriptorFor(desc.ofClass) != null) {
  1272. return;
  1273. }
  1274. int hash = desc.ofClass.hashCode();
  1275. int index = (hash & 0x7FFFFFFF) % descriptorFor.length;
  1276. ObjectStreamClassEntry e = new ObjectStreamClassEntry(desc);
  1277. e.next = descriptorFor[index];
  1278. descriptorFor[index] = e;
  1279. }
  1280. private static Field[] getDeclaredFields(final Class clz) {
  1281. return (Field[]) AccessController.doPrivileged(new PrivilegedAction() {
  1282. public Object run() {
  1283. return clz.getDeclaredFields();
  1284. }
  1285. });
  1286. }
  1287. /*
  1288. * The name of this descriptor
  1289. */
  1290. private String name;
  1291. /*
  1292. * The descriptor of the supertype.
  1293. */
  1294. private ObjectStreamClass superclass;
  1295. /*
  1296. * Flags for Serializable and Externalizable.
  1297. */
  1298. private boolean serializable;
  1299. private boolean externalizable;
  1300. /*
  1301. * Array of persistent fields of this class, sorted by
  1302. * type and name.
  1303. */
  1304. private ObjectStreamField[] fields;
  1305. /*
  1306. * Class that is a descriptor for in this virtual machine.
  1307. */
  1308. private Class ofClass;
  1309. /*
  1310. * True if descriptor for a proxy class.
  1311. */
  1312. boolean forProxyClass;
  1313. /*
  1314. * SerialVersionUID for this class.
  1315. */
  1316. private long suid = kDefaultUID;
  1317. private String suidStr = null;
  1318. /*
  1319. * Actual (computed) SerialVersionUID for this class.
  1320. */
  1321. private long actualSuid = kDefaultUID;
  1322. private String actualSuidStr = null;
  1323. /*
  1324. * The total number of bytes of primitive fields.
  1325. * The total number of object fields.
  1326. */
  1327. int primBytes;
  1328. int objFields;
  1329. /**
  1330. * Flag indicating whether or not this instance has
  1331. * successfully completed initialization. This is to
  1332. * try to fix bug 4373844. Working to move to
  1333. * reusing java.io.ObjectStreamClass for JDK 1.5.
  1334. */
  1335. private boolean initialized = false;
  1336. /* Internal lock object. */
  1337. private Object lock = new Object();
  1338. /* In JDK 1.1, external data was not written in block mode.
  1339. * As of JDK 1.2, external data is written in block data mode. This
  1340. * flag enables JDK 1.2 to be able to read JDK 1.1 written external data.
  1341. *
  1342. * @since JDK 1.2
  1343. */
  1344. private boolean hasExternalizableBlockData;
  1345. Method writeObjectMethod;
  1346. Method readObjectMethod;
  1347. private Method writeReplaceObjectMethod;
  1348. private Method readResolveObjectMethod;
  1349. private Constructor cons ;
  1350. /**
  1351. * Beginning in Java to IDL ptc/02-01-12, RMI-IIOP has a
  1352. * stream format version 2 which puts a fake valuetype around
  1353. * a Serializable's optional custom data. This valuetype has
  1354. * a special repository ID made from the Serializable's
  1355. * information which we are pre-computing and
  1356. * storing here.
  1357. */
  1358. private String rmiiiopOptionalDataRepId = null;
  1359. /*
  1360. * ObjectStreamClass that this one was built from.
  1361. */
  1362. private ObjectStreamClass localClassDesc;
  1363. /* Find out if the class has a static class initializer <clinit> */
  1364. private static Method hasStaticInitializerMethod = null;
  1365. /**
  1366. * Returns true if the given class defines a static initializer method,
  1367. * false otherwise.
  1368. */
  1369. private static boolean hasStaticInitializer(Class cl) {
  1370. if (hasStaticInitializerMethod == null) {
  1371. Class classWithThisMethod = null;
  1372. try {
  1373. try {
  1374. // When using rip-int with Merlin or when this is a Merlin
  1375. // workspace, the method we want is in sun.misc.ClassReflector
  1376. // and absent from java.io.ObjectStreamClass.
  1377. //
  1378. // When compiling rip-int with JDK 1.3.x, we have to get it
  1379. // from java.io.ObjectStreamClass.
  1380. classWithThisMethod = Class.forName("sun.misc.ClassReflector");
  1381. } catch (ClassNotFoundException cnfe) {
  1382. // Do nothing. This is either not a Merlin workspace,
  1383. // or rip-int is being compiled with something other than
  1384. // Merlin, probably JDK 1.3. Fall back on java.io.ObjectStreaClass.
  1385. }
  1386. if (classWithThisMethod == null)
  1387. classWithThisMethod = java.io.ObjectStreamClass.class;
  1388. hasStaticInitializerMethod =
  1389. classWithThisMethod.getDeclaredMethod("hasStaticInitializer",
  1390. new Class[] { Class.class });
  1391. } catch (NoSuchMethodException ex) {
  1392. }
  1393. if (hasStaticInitializerMethod == null) {
  1394. // XXX I18N, logging needed
  1395. throw new InternalError("Can't find hasStaticInitializer method on "
  1396. + classWithThisMethod.getName());
  1397. }
  1398. hasStaticInitializerMethod.setAccessible(true);
  1399. }
  1400. try {
  1401. Boolean retval = (Boolean)
  1402. hasStaticInitializerMethod.invoke(null, new Object[] { cl });
  1403. return retval.booleanValue();
  1404. } catch (Exception ex) {
  1405. // XXX I18N, logging needed
  1406. InternalError ie = new InternalError( "Error invoking hasStaticInitializer" ) ;
  1407. ie.initCause( ex ) ;
  1408. throw ie ;
  1409. }
  1410. }
  1411. /* The Class Object for java.io.Serializable */
  1412. private static Class classSerializable = null;
  1413. private static Class classExternalizable = null;
  1414. /*
  1415. * Resolve java.io.Serializable at load time.
  1416. */
  1417. static {
  1418. try {
  1419. classSerializable = Class.forName("java.io.Serializable");
  1420. classExternalizable = Class.forName("java.io.Externalizable");
  1421. } catch (Throwable e) {
  1422. System.err.println("Could not load java.io.Serializable or java.io.Externalizable.");
  1423. }
  1424. }
  1425. /** use serialVersionUID from JDK 1.1. for interoperability */
  1426. private static final long serialVersionUID = -6120832682080437368L;
  1427. /**
  1428. * Set serialPersistentFields of a Serializable class to this value to
  1429. * denote that the class has no Serializable fields.
  1430. */
  1431. public static final ObjectStreamField[] NO_FIELDS =
  1432. new ObjectStreamField[0];
  1433. /*
  1434. * Entries held in the Cache of known ObjectStreamClass objects.
  1435. * Entries are chained together with the same hash value (modulo array size).
  1436. */
  1437. private static class ObjectStreamClassEntry // extends java.lang.ref.SoftReference
  1438. {
  1439. ObjectStreamClassEntry(ObjectStreamClass c) {
  1440. //super(c);
  1441. this.c = c;
  1442. }
  1443. ObjectStreamClassEntry next;
  1444. public Object get()
  1445. {
  1446. return c;
  1447. }
  1448. private ObjectStreamClass c;
  1449. }
  1450. /*
  1451. * Comparator object for Classes and Interfaces
  1452. */
  1453. private static Comparator compareClassByName =
  1454. new CompareClassByName();
  1455. private static class CompareClassByName implements Comparator {
  1456. public int compare(Object o1, Object o2) {
  1457. Class c1 = (Class)o1;
  1458. Class c2 = (Class)o2;
  1459. return (c1.getName()).compareTo(c2.getName());
  1460. }
  1461. }
  1462. /**
  1463. * Comparator for ObjectStreamFields by name
  1464. */
  1465. private final static Comparator compareObjStrFieldsByName
  1466. = new CompareObjStrFieldsByName();
  1467. private static class CompareObjStrFieldsByName implements Comparator {
  1468. public int compare(Object o1, Object o2) {
  1469. ObjectStreamField osf1 = (ObjectStreamField)o1;
  1470. ObjectStreamField osf2 = (ObjectStreamField)o2;
  1471. return osf1.getName().compareTo(osf2.getName());
  1472. }
  1473. }
  1474. /*
  1475. * Comparator object for Members, Fields, and Methods
  1476. */
  1477. private static Comparator compareMemberByName =
  1478. new CompareMemberByName();
  1479. private static class CompareMemberByName implements Comparator {
  1480. public int compare(Object o1, Object o2) {
  1481. String s1 = ((Member)o1).getName();
  1482. String s2 = ((Member)o2).getName();
  1483. if (o1 instanceof Method) {
  1484. s1 += getSignature((Method)o1);
  1485. s2 += getSignature((Method)o2);
  1486. } else if (o1 instanceof Constructor) {
  1487. s1 += getSignature((Constructor)o1);
  1488. s2 += getSignature((Constructor)o2);
  1489. }
  1490. return s1.compareTo(s2);
  1491. }
  1492. }
  1493. /* It is expensive to recompute a method or constructor signature
  1494. many times, so compute it only once using this data structure. */
  1495. private static class MethodSignature implements Comparator {
  1496. Member member;
  1497. String signature; // cached parameter signature
  1498. /* Given an array of Method or Constructor members,
  1499. return a sorted array of the non-private members.*/
  1500. /* A better implementation would be to implement the returned data
  1501. structure as an insertion sorted link list.*/
  1502. static MethodSignature[] removePrivateAndSort(Member[] m) {
  1503. int numNonPrivate = 0;
  1504. for (int i = 0; i < m.length; i++) {
  1505. if (! Modifier.isPrivate(m[i].getModifiers())) {
  1506. numNonPrivate++;
  1507. }
  1508. }
  1509. MethodSignature[] cm = new MethodSignature[numNonPrivate];
  1510. int cmi = 0;
  1511. for (int i = 0; i < m.length; i++) {
  1512. if (! Modifier.isPrivate(m[i].getModifiers())) {
  1513. cm[cmi] = new MethodSignature(m[i]);
  1514. cmi++;
  1515. }
  1516. }
  1517. if (cmi > 0)
  1518. Arrays.sort(cm, cm[0]);
  1519. return cm;
  1520. }
  1521. /* Assumes that o1 and o2 are either both methods
  1522. or both constructors.*/
  1523. public int compare(Object o1, Object o2) {
  1524. /* Arrays.sort calls compare when o1 and o2 are equal.*/
  1525. if (o1 == o2)
  1526. return 0;
  1527. MethodSignature c1 = (MethodSignature)o1;
  1528. MethodSignature c2 = (MethodSignature)o2;
  1529. int result;
  1530. if (isConstructor()) {
  1531. result = c1.signature.compareTo(c2.signature);
  1532. } else { // is a Method.
  1533. result = c1.member.getName().compareTo(c2.member.getName());
  1534. if (result == 0)
  1535. result = c1.signature.compareTo(c2.signature);
  1536. }
  1537. return result;
  1538. }
  1539. final private boolean isConstructor() {
  1540. return member instanceof Constructor;
  1541. }
  1542. private MethodSignature(Member m) {
  1543. member = m;
  1544. if (isConstructor()) {
  1545. signature = ObjectStreamClass.getSignature((Constructor)m);
  1546. } else {
  1547. signature = ObjectStreamClass.getSignature((Method)m);
  1548. }
  1549. }
  1550. }
  1551. /**
  1552. * Returns non-static, non-abstract method with given signature provided it
  1553. * is defined by or accessible (via inheritance) by the given class, or
  1554. * null if no match found. Access checks are disabled on the returned
  1555. * method (if any).
  1556. *
  1557. * Copied from the Merlin java.io.ObjectStreamClass.
  1558. */
  1559. private static Method getInheritableMethod(Class cl, String name,
  1560. Class[] argTypes,
  1561. Class returnType)
  1562. {
  1563. Method meth = null;
  1564. Class defCl = cl;
  1565. while (defCl != null) {
  1566. try {
  1567. meth = defCl.getDeclaredMethod(name, argTypes);
  1568. break;
  1569. } catch (NoSuchMethodException ex) {
  1570. defCl = defCl.getSuperclass();
  1571. }
  1572. }
  1573. if ((meth == null) || (meth.getReturnType() != returnType)) {
  1574. return null;
  1575. }
  1576. meth.setAccessible(true);
  1577. int mods = meth.getModifiers();
  1578. if ((mods & (Modifier.STATIC | Modifier.ABSTRACT)) != 0) {
  1579. return null;
  1580. } else if ((mods & (Modifier.PUBLIC | Modifier.PROTECTED)) != 0) {
  1581. return meth;
  1582. } else if ((mods & Modifier.PRIVATE) != 0) {
  1583. return (cl == defCl) ? meth : null;
  1584. } else {
  1585. return packageEquals(cl, defCl) ? meth : null;
  1586. }
  1587. }
  1588. /**
  1589. * Returns true if classes are defined in the same package, false
  1590. * otherwise.
  1591. *
  1592. * Copied from the Merlin java.io.ObjectStreamClass.
  1593. */
  1594. private static boolean packageEquals(Class cl1, Class cl2) {
  1595. Package pkg1 = cl1.getPackage(), pkg2 = cl2.getPackage();
  1596. return ((pkg1 == pkg2) || ((pkg1 != null) && (pkg1.equals(pkg2))));
  1597. }
  1598. }