1. /*
  2. * @(#)ObjectStreamClass.java 1.35 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.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 org.omg.CORBA.ValueMember;
  40. /**
  41. * A ObjectStreamClass describes a class that can be serialized to a stream
  42. * or a class that was serialized to a stream. It contains the name
  43. * and the serialVersionUID of the class.
  44. * <br>
  45. * The ObjectStreamClass for a specific class loaded in this Java VM can
  46. * be found using the lookup method.
  47. *
  48. * @author Roger Riggs
  49. * @(#)ObjectStreamClass.java 1.17 99/06/07
  50. * @since JDK1.1
  51. */
  52. public class ObjectStreamClass implements java.io.Serializable {
  53. public static final long kDefaultUID = -1;
  54. private static Object noArgsList[] = {};
  55. private static Class noTypesList[] = {};
  56. private static Hashtable translatedFields;
  57. static {
  58. try{
  59. Class.forName("com.sun.corba.se.internal.io.LibraryManager").getDeclaredMethod("load",null).invoke(null,null);
  60. }
  61. catch(Throwable t){}
  62. }
  63. /** Find the descriptor for a class that can be serialized. Null
  64. * is returned if the specified class does not implement
  65. * java.io.Serializable or java.io.Externalizable.
  66. */
  67. static final ObjectStreamClass lookup(Class cl)
  68. {
  69. ObjectStreamClass desc = lookupInternal(cl);
  70. if (desc.isSerializable() || desc.isExternalizable())
  71. return desc;
  72. return null;
  73. }
  74. /*
  75. * Find the class descriptor for the specified class.
  76. * Package access only so it can be called from ObjectIn/OutStream.
  77. */
  78. static ObjectStreamClass lookupInternal(Class cl)
  79. {
  80. /* Synchronize on the hashtable so no two threads will do
  81. * this at the same time.
  82. */
  83. ObjectStreamClass desc = null;
  84. synchronized (descriptorFor) {
  85. /* Find the matching descriptor if it already known */
  86. desc = findDescriptorFor(cl);
  87. if (desc == null) {
  88. /* Check if it's serializable */
  89. boolean serializable = classSerializable.isAssignableFrom(cl);
  90. /* If the class is only Serializable,
  91. * lookup the descriptor for the superclass.
  92. */
  93. ObjectStreamClass superdesc = null;
  94. if (serializable) {
  95. Class superclass = cl.getSuperclass();
  96. if (superclass != null)
  97. superdesc = lookup(superclass);
  98. }
  99. /* Check if its' externalizable.
  100. * If it's Externalizable, clear the serializable flag.
  101. * Only one or the other may be set in the protocol.
  102. */
  103. boolean externalizable = false;
  104. if (serializable) {
  105. externalizable =
  106. ((superdesc != null) && superdesc.isExternalizable()) ||
  107. classExternalizable.isAssignableFrom(cl);
  108. if (externalizable) {
  109. serializable = false;
  110. }
  111. }
  112. /* Create a new version descriptor,
  113. * it put itself in the known table.
  114. */
  115. desc = new ObjectStreamClass(cl, superdesc,
  116. serializable, externalizable);
  117. }
  118. }
  119. // Must always call init. See bug 4488137. This code was
  120. // incorrectly changed to return immediately on a non-null
  121. // cache result. That allowed threads to gain access to
  122. // unintialized instances.
  123. //
  124. // All threads must sync on the member variable lock
  125. // and check the initialization state.
  126. //
  127. // An alternative is to continue to synchronize on the
  128. // descriptorFor array, but that leads to poor performance
  129. // (see bug 4165204 "ObjectStreamClass can hold global lock
  130. // for a very long time").
  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 theosc = ObjectStreamClass.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 theosc = ObjectStreamClass.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.
  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 from a loaded class.
  290. * Don't call this directly, call lookup instead.
  291. */
  292. private ObjectStreamClass(java.lang.Class cl, ObjectStreamClass 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 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. // See description at definition of initialized.
  328. if (initialized)
  329. return;
  330. final Class cl = ofClass;
  331. if (!serializable ||
  332. externalizable ||
  333. forProxyClass ||
  334. name.equals("java.lang.String")) {
  335. fields = NO_FIELDS;
  336. } else if (serializable) {
  337. /* Ask for permission to override field access checks.
  338. */
  339. AccessController.doPrivileged(new PrivilegedAction() {
  340. public Object run() {
  341. /* Fill in the list of persistent fields.
  342. * If it is declared, use the declared serialPersistentFields.
  343. * Otherwise, extract the fields from the class itself.
  344. */
  345. try {
  346. Field pf = cl.getDeclaredField("serialPersistentFields");
  347. // serial bug 7; the serialPersistentFields were not
  348. // being read and stored as Accessible bit was not set
  349. pf.setAccessible(true);
  350. // serial bug 7; need to find if the field is of type
  351. // java.io.ObjectStreamField
  352. java.io.ObjectStreamField[] f =
  353. (java.io.ObjectStreamField[])pf.get(cl);
  354. int mods = pf.getModifiers();
  355. if ((Modifier.isPrivate(mods)) &&
  356. (Modifier.isStatic(mods)) &&
  357. (Modifier.isFinal(mods)))
  358. {
  359. fields = (ObjectStreamField[])translateFields((Object[])pf.get(cl));
  360. }
  361. } catch (NoSuchFieldException e) {
  362. fields = null;
  363. } catch (IllegalAccessException e) {
  364. fields = null;
  365. } catch (IllegalArgumentException e) {
  366. fields = null;
  367. } catch (ClassCastException e) {
  368. /* Thrown if a field serialPersistentField exists
  369. * but it is not of type ObjectStreamField.
  370. */
  371. fields = null;
  372. }
  373. if (fields == null) {
  374. /* Get all of the declared fields for this
  375. * Class. setAccessible on all fields so they
  376. * can be accessed later. Create a temporary
  377. * ObjectStreamField array to hold each
  378. * non-static, non-transient field. Then copy the
  379. * temporary array into an array of the correct
  380. * size once the number of fields is known.
  381. */
  382. Field[] actualfields = cl.getDeclaredFields();
  383. int numFields = 0;
  384. ObjectStreamField[] tempFields =
  385. new ObjectStreamField[actualfields.length];
  386. for (int i = 0; i < actualfields.length; i++) {
  387. int modifiers = actualfields[i].getModifiers();
  388. if (!Modifier.isStatic(modifiers) &&
  389. !Modifier.isTransient(modifiers)) {
  390. tempFields[numFields++] =
  391. new com.sun.corba.se.internal.io.ObjectStreamField(actualfields[i]);
  392. }
  393. }
  394. fields = new ObjectStreamField[numFields];
  395. System.arraycopy(tempFields, 0, fields, 0, numFields);
  396. } else {
  397. // For each declared persistent field, look for an actual
  398. // reflected Field. If there is one, make sure it's the correct
  399. // type and cache it in the ObjectStreamClass for that field.
  400. for (int j = fields.length-1; j >= 0; j--) {
  401. try {
  402. Field reflField = cl.getDeclaredField(fields[j].getName());
  403. if (fields[j].getType() == reflField.getType()) {
  404. // reflField.setAccessible(true);
  405. fields[j].setField(reflField);
  406. }
  407. } catch (NoSuchFieldException e) {
  408. // Nothing to do
  409. }
  410. }
  411. }
  412. return null;
  413. }
  414. });
  415. if (fields.length > 1)
  416. Arrays.sort(fields);
  417. /* Set up field data for use while writing using the API api. */
  418. computeFieldInfo();
  419. }
  420. /* Get the serialVersionUID from the class.
  421. * It uses the access override mechanism so make sure
  422. * the field objects is only used here.
  423. *
  424. * NonSerializable classes have a serialVerisonUID of 0L.
  425. */
  426. if (isNonSerializable()) {
  427. suid = 0L;
  428. } else {
  429. // Lookup special Serializable members using reflection.
  430. AccessController.doPrivileged(new PrivilegedAction() {
  431. public Object run() {
  432. if (forProxyClass) {
  433. // proxy classes always have serialVersionUID of 0L
  434. suid = 0L;
  435. } else {
  436. try {
  437. final Field f = cl.getDeclaredField("serialVersionUID");
  438. int mods = f.getModifiers();
  439. // SerialBug 5: static final SUID should be read
  440. if (Modifier.isStatic(mods) &&
  441. Modifier.isFinal(mods) ) {
  442. f.setAccessible(true);
  443. suid = f.getLong(cl);
  444. // get rid of native code
  445. // suid = getSerialVersionUIDField(cl);
  446. // SerialBug 2: should be computed after writeObject
  447. // actualSuid = computeStructuralUID(cl);
  448. } else {
  449. suid = _computeSerialVersionUID(cl);
  450. // SerialBug 2: should be computed after writeObject
  451. // actualSuid = computeStructuralUID(cl);
  452. }
  453. } catch (NoSuchFieldException ex) {
  454. suid = _computeSerialVersionUID(cl);
  455. // SerialBug 2: should be computed after writeObject
  456. // actualSuid = computeStructuralUID(cl);
  457. } catch (IllegalAccessException ex) {
  458. suid = _computeSerialVersionUID(cl);
  459. }
  460. }
  461. writeReplaceObjectMethod
  462. = ObjectStreamClass.getInheritableMethod(cl,
  463. "writeReplace",
  464. noTypesList,
  465. Object.class);
  466. readResolveObjectMethod
  467. = ObjectStreamClass.getInheritableMethod(cl,
  468. "readResolve",
  469. noTypesList,
  470. Object.class);
  471. /* Cache lookup of writeObject and readObject for
  472. * Serializable classes. (Do not lookup for
  473. * Externalizable)
  474. */
  475. if (serializable && !forProxyClass) {
  476. /* Look for the writeObject method
  477. * Set the accessible flag on it here. ObjectOutputStream
  478. * will call it as necessary.
  479. */
  480. try {
  481. Class[] args = {java.io.ObjectOutputStream.class};
  482. writeObjectMethod = cl.getDeclaredMethod("writeObject", args);
  483. hasWriteObjectMethod = true;
  484. int mods = writeObjectMethod.getModifiers();
  485. // Method must be private and non-static
  486. if (!Modifier.isPrivate(mods) ||
  487. Modifier.isStatic(mods)) {
  488. writeObjectMethod = null;
  489. hasWriteObjectMethod = false;
  490. }
  491. } catch (NoSuchMethodException e) {
  492. }
  493. /* Look for the readObject method
  494. * set the access override and save the reference for
  495. * ObjectInputStream so it can all the method directly.
  496. */
  497. try {
  498. Class[] args = {java.io.ObjectInputStream.class};
  499. readObjectMethod = cl.getDeclaredMethod("readObject", args);
  500. int mods = readObjectMethod.getModifiers();
  501. // Method must be private and non-static
  502. if (!Modifier.isPrivate(mods) ||
  503. Modifier.isStatic(mods)) {
  504. readObjectMethod = null;
  505. }
  506. } catch (NoSuchMethodException e) {
  507. }
  508. // Compute the structural UID. This must be done after the
  509. // calculation for writeObject. Fixed 4/20/2000, eea1
  510. // SerialBug 2: to have correct value in RepId
  511. }
  512. return null;
  513. }
  514. });
  515. }
  516. // This call depends on a lot of information computed above!
  517. actualSuid = ObjectStreamClass.computeStructuralUID(this, cl);
  518. // This must be done last.
  519. initialized = true;
  520. }
  521. }
  522. /*
  523. * Create an empty ObjectStreamClass for a class about to be read.
  524. * This is separate from read so ObjectInputStream can assign the
  525. * wire handle early, before any nested ObjectStreamClass might
  526. * be read.
  527. */
  528. ObjectStreamClass(String n, long s) {
  529. name = n;
  530. suid = s;
  531. superclass = null;
  532. }
  533. private static Object[] translateFields(Object objs[])
  534. throws NoSuchFieldException {
  535. try{
  536. java.io.ObjectStreamField fields[] = (java.io.ObjectStreamField[])objs;
  537. Object translation[] = null;
  538. if (translatedFields == null)
  539. translatedFields = new Hashtable();
  540. translation = (Object[])translatedFields.get(fields);
  541. if (translation != null)
  542. return translation;
  543. else {
  544. Class osfClass = Class.forName("com.sun.corba.se.internal.io.ObjectStreamField");
  545. translation = (Object[])java.lang.reflect.Array.newInstance(osfClass, objs.length);
  546. Object arg[] = new Object[2];
  547. Class types[] = {String.class, Class.class};
  548. Constructor constructor = osfClass.getDeclaredConstructor(types);
  549. for (int i = fields.length -1; i >= 0; i--){
  550. arg[0] = fields[i].getName();
  551. arg[1] = fields[i].getType();
  552. translation[i] = constructor.newInstance(arg);
  553. }
  554. translatedFields.put(fields, translation);
  555. }
  556. return (Object[])translation;
  557. }
  558. catch(Throwable t){
  559. throw new NoSuchFieldException();
  560. }
  561. }
  562. /*
  563. * Set the class this version descriptor matches.
  564. * The base class name and serializable hash must match.
  565. * Fill in the reflected Fields that will be used
  566. * for reading.
  567. */
  568. final void setClass(Class cl) throws InvalidClassException {
  569. if (cl == null) {
  570. localClassDesc = null;
  571. ofClass = null;
  572. computeFieldInfo();
  573. return;
  574. }
  575. localClassDesc = lookupInternal(cl);
  576. if (localClassDesc == null)
  577. throw new InvalidClassException(cl.getName(),
  578. "Local class not compatible");
  579. if (suid != localClassDesc.suid) {
  580. /* Check for exceptional cases that allow mismatched suid. */
  581. /* Allow adding Serializable or Externalizable
  582. * to a later release of the class.
  583. */
  584. boolean addedSerialOrExtern =
  585. isNonSerializable() || localClassDesc.isNonSerializable();
  586. /* Disregard the serialVersionUID of an array
  587. * when name and cl.Name differ. If resolveClass() returns
  588. * an array with a different package name,
  589. * the serialVersionUIDs will not match since the fully
  590. * qualified array class is used in the
  591. * computation of the array's serialVersionUID. There is
  592. * no way to set a permanent serialVersionUID for an array type.
  593. */
  594. boolean arraySUID = (cl.isArray() && ! cl.getName().equals(name));
  595. if (! arraySUID && ! addedSerialOrExtern ) {
  596. throw new InvalidClassException(cl.getName(),
  597. "Local class not compatible:" +
  598. " stream classdesc serialVersionUID=" + suid +
  599. " local class serialVersionUID=" + localClassDesc.suid);
  600. }
  601. }
  602. /* compare the class names, stripping off package names. */
  603. if (! compareClassNames(name, cl.getName(), '.'))
  604. throw new InvalidClassException(cl.getName(),
  605. "Incompatible local class name. " +
  606. "Expected class name compatible with " +
  607. name);
  608. /*
  609. * Test that both implement either serializable or externalizable.
  610. */
  611. // The next check is more generic, since it covers the
  612. // Proxy case, the JDK 1.3 serialization code has
  613. // both checks
  614. //if ((serializable && localClassDesc.externalizable) ||
  615. // (externalizable && localClassDesc.serializable))
  616. // throw new InvalidClassException(localCl.getName(),
  617. // "Serializable is incompatible with Externalizable");
  618. if ((serializable != localClassDesc.serializable) ||
  619. (externalizable != localClassDesc.externalizable) ||
  620. (!serializable && !externalizable))
  621. throw new InvalidClassException(cl.getName(),
  622. "Serialization incompatible with Externalization");
  623. /* Set up the reflected Fields in the class where the value of each
  624. * field in this descriptor should be stored.
  625. * Each field in this ObjectStreamClass (the source) is located (by
  626. * name) in the ObjectStreamClass of the class(the destination).
  627. * In the usual (non-versioned case) the field is in both
  628. * descriptors and the types match, so the reflected Field is copied.
  629. * If the type does not match, a InvalidClass exception is thrown.
  630. * If the field is not present in the class, the reflected Field
  631. * remains null so the field will be read but discarded.
  632. * If extra fields are present in the class they are ignored. Their
  633. * values will be set to the default value by the object allocator.
  634. * Both the src and dest field list are sorted by type and name.
  635. */
  636. ObjectStreamField[] destfield =
  637. (ObjectStreamField[])localClassDesc.fields;
  638. ObjectStreamField[] srcfield =
  639. (ObjectStreamField[])fields;
  640. int j = 0;
  641. nextsrc:
  642. for (int i = 0; i < srcfield.length; i++ ) {
  643. /* Find this field in the dest*/
  644. for (int k = j; k < destfield.length; k++) {
  645. if (srcfield[i].getName().equals(destfield[k].getName())) {
  646. /* found match */
  647. if (srcfield[i].isPrimitive() &&
  648. !srcfield[i].typeEquals(destfield[k])) {
  649. throw new InvalidClassException(cl.getName(),
  650. "The type of field " +
  651. srcfield[i].getName() +
  652. " of class " + name +
  653. " is incompatible.");
  654. }
  655. /* Skip over any fields in the dest that are not in the src */
  656. j = k;
  657. srcfield[i].setField(destfield[j].getField());
  658. // go on to the next source field
  659. continue nextsrc;
  660. }
  661. }
  662. }
  663. /* Set up field data for use while reading from the input stream. */
  664. computeFieldInfo();
  665. /* Remember the class this represents */
  666. ofClass = cl;
  667. /* get the cache of these methods from the local class
  668. * implementation.
  669. */
  670. readObjectMethod = localClassDesc.readObjectMethod;
  671. readResolveObjectMethod = localClassDesc.readResolveObjectMethod;
  672. /* Look for the readObject method
  673. * set the access override and save the reference for
  674. * ObjectInputStream so it can all the method directly.
  675. */
  676. /*****
  677. try {
  678. Class[] args = {java.io.ObjectInputStream.class};
  679. readObjectMethod = ObjectStreamClass.getDeclaredMethod(cl,"readObject", args);
  680. int mods = readObjectMethod.getModifiers();
  681. // Method must be private and non-static
  682. if (!Modifier.isPrivate(mods) ||
  683. Modifier.isStatic(mods)) {
  684. readObjectMethod = null;
  685. }
  686. } catch (NoSuchMethodException e) {
  687. }
  688. *****/
  689. }
  690. /* Compare the base class names of streamName and localName.
  691. *
  692. * @return Return true iff the base class name compare.
  693. * @parameter streamName Fully qualified class name.
  694. * @parameter localName Fully qualified class name.
  695. * @parameter pkgSeparator class names use either '.' or '/'.
  696. *
  697. * Only compare base class name to allow package renaming.
  698. */
  699. static boolean compareClassNames(String streamName,
  700. String localName,
  701. char pkgSeparator) {
  702. /* compare the class names, stripping off package names. */
  703. int streamNameIndex = streamName.lastIndexOf(pkgSeparator);
  704. if (streamNameIndex < 0)
  705. streamNameIndex = 0;
  706. int localNameIndex = localName.lastIndexOf(pkgSeparator);
  707. if (localNameIndex < 0)
  708. localNameIndex = 0;
  709. return streamName.regionMatches(false, streamNameIndex,
  710. localName, localNameIndex,
  711. streamName.length() - streamNameIndex);
  712. }
  713. /*
  714. * Compare the types of two class descriptors.
  715. * They match if they have the same class name and suid
  716. */
  717. final boolean typeEquals(ObjectStreamClass other) {
  718. return (suid == other.suid) &&
  719. compareClassNames(name, other.name, '.');
  720. }
  721. /*
  722. * Return the superclass descriptor of this descriptor.
  723. */
  724. final void setSuperclass(ObjectStreamClass s) {
  725. superclass = s;
  726. }
  727. /*
  728. * Return the superclass descriptor of this descriptor.
  729. */
  730. final ObjectStreamClass getSuperclass() {
  731. return superclass;
  732. }
  733. /*
  734. * Return whether the class has a writeObject method
  735. */
  736. final boolean hasWriteObject() {
  737. return hasWriteObjectMethod;
  738. }
  739. final boolean isCustomMarshaled() {
  740. return (hasWriteObject() || isExternalizable());
  741. }
  742. /*
  743. * Return true if all instances of 'this' Externalizable class
  744. * are written in block-data mode from the stream that 'this' was read
  745. * from. <p>
  746. *
  747. * In JDK 1.1, all Externalizable instances are not written
  748. * in block-data mode.
  749. * In JDK 1.2, all Externalizable instances, by default, are written
  750. * in block-data mode and the Externalizable instance is terminated with
  751. * tag TC_ENDBLOCKDATA. Change enabled the ability to skip Externalizable
  752. * instances.
  753. *
  754. * IMPLEMENTATION NOTE:
  755. * This should have been a mode maintained per stream; however,
  756. * for compatibility reasons, it was only possible to record
  757. * this change per class. All Externalizable classes within
  758. * a given stream should either have this mode enabled or
  759. * disabled. This is enforced by not allowing the PROTOCOL_VERSION
  760. * of a stream to he changed after any objects have been written.
  761. *
  762. * @see ObjectOuputStream#useProtocolVersion
  763. * @see ObjectStreamConstants#PROTOCOL_VERSION_1
  764. * @see ObjectStreamConstants#PROTOCOL_VERSION_2
  765. *
  766. * @since JDK 1.2
  767. */
  768. boolean hasExternalizableBlockDataMode() {
  769. return hasExternalizableBlockData;
  770. }
  771. /*
  772. * Return the ObjectStreamClass of the local class this one is based on.
  773. */
  774. final ObjectStreamClass localClassDescriptor() {
  775. return localClassDesc;
  776. }
  777. /*
  778. * Get the Serializability of the class.
  779. */
  780. boolean isSerializable() {
  781. return serializable;
  782. }
  783. /*
  784. * Get the externalizability of the class.
  785. */
  786. boolean isExternalizable() {
  787. return externalizable;
  788. }
  789. boolean isNonSerializable() {
  790. return ! (externalizable || serializable);
  791. }
  792. /*
  793. * Calculate the size of the array needed to store primitive data and the
  794. * number of object references to read when reading from the input
  795. * stream.
  796. */
  797. private void computeFieldInfo() {
  798. primBytes = 0;
  799. objFields = 0;
  800. for (int i = 0; i < fields.length; i++ ) {
  801. switch (fields[i].getTypeCode()) {
  802. case 'B':
  803. case 'Z':
  804. primBytes += 1;
  805. break;
  806. case 'C':
  807. case 'S':
  808. primBytes += 2;
  809. break;
  810. case 'I':
  811. case 'F':
  812. primBytes += 4;
  813. break;
  814. case 'J':
  815. case 'D' :
  816. primBytes += 8;
  817. break;
  818. case 'L':
  819. case '[':
  820. objFields += 1;
  821. break;
  822. }
  823. }
  824. }
  825. /*
  826. * Compute a hash for the specified class. Incrementally add
  827. * items to the hash accumulating in the digest stream.
  828. * Fold the hash into a long. Use the SHA secure hash function.
  829. */
  830. private static long _computeSerialVersionUID(Class cl) {
  831. ByteArrayOutputStream devnull = new ByteArrayOutputStream(512);
  832. long h = 0;
  833. try {
  834. MessageDigest md = MessageDigest.getInstance("SHA");
  835. DigestOutputStream mdo = new DigestOutputStream(devnull, md);
  836. DataOutputStream data = new DataOutputStream(mdo);
  837. data.writeUTF(cl.getName());
  838. int classaccess = cl.getModifiers();
  839. classaccess &= (Modifier.PUBLIC | Modifier.FINAL |
  840. Modifier.INTERFACE | Modifier.ABSTRACT);
  841. /* Workaround for javac bug that only set ABSTRACT for
  842. * interfaces if the interface had some methods.
  843. * The ABSTRACT bit reflects that the number of methods > 0.
  844. * This is required so correct hashes can be computed
  845. * for existing class files.
  846. * Previously this hack was previously present in the VM.
  847. */
  848. Method[] method = cl.getDeclaredMethods();
  849. if ((classaccess & Modifier.INTERFACE) != 0) {
  850. classaccess &= (~Modifier.ABSTRACT);
  851. if (method.length > 0) {
  852. classaccess |= Modifier.ABSTRACT;
  853. }
  854. }
  855. data.writeInt(classaccess);
  856. /*
  857. * Get the list of interfaces supported,
  858. * Accumulate their names their names in Lexical order
  859. * and add them to the hash
  860. */
  861. if (!cl.isArray()) {
  862. /* In 1.2fcs, getInterfaces() was modified to return
  863. * {java.lang.Cloneable, java.io.Serializable} when
  864. * called on array classes. These values would upset
  865. * the computation of the hash, so we explicitly omit
  866. * them from its computation.
  867. */
  868. Class interfaces[] = cl.getInterfaces();
  869. Arrays.sort(interfaces, compareClassByName);
  870. for (int i = 0; i < interfaces.length; i++) {
  871. data.writeUTF(interfaces[i].getName());
  872. }
  873. }
  874. /* Sort the field names to get a deterministic order */
  875. Field[] field = cl.getDeclaredFields();
  876. Arrays.sort(field, compareMemberByName);
  877. for (int i = 0; i < field.length; i++) {
  878. Field f = field[i];
  879. /* Include in the hash all fields except those that are
  880. * private transient and private static.
  881. */
  882. int m = f.getModifiers();
  883. if (Modifier.isPrivate(m) &&
  884. (Modifier.isTransient(m) || Modifier.isStatic(m)))
  885. continue;
  886. data.writeUTF(f.getName());
  887. data.writeInt(m);
  888. data.writeUTF(getSignature(f.getType()));
  889. }
  890. if (hasStaticInitializer(cl)) {
  891. data.writeUTF("<clinit>");
  892. data.writeInt(Modifier.STATIC); // TBD: what modifiers does it have
  893. data.writeUTF("()V");
  894. }
  895. /*
  896. * Get the list of constructors including name and signature
  897. * Sort lexically, add all except the private constructors
  898. * to the hash with their access flags
  899. */
  900. MethodSignature[] constructors =
  901. MethodSignature.removePrivateAndSort(cl.getDeclaredConstructors());
  902. for (int i = 0; i < constructors.length; i++) {
  903. MethodSignature c = constructors[i];
  904. String mname = "<init>";
  905. String desc = c.signature;
  906. desc = desc.replace('/', '.');
  907. data.writeUTF(mname);
  908. data.writeInt(c.member.getModifiers());
  909. data.writeUTF(desc);
  910. }
  911. /* Include in the hash all methods except those that are
  912. * private transient and private static.
  913. */
  914. MethodSignature[] methods =
  915. MethodSignature.removePrivateAndSort(method);
  916. for (int i = 0; i < methods.length; i++ ) {
  917. MethodSignature m = methods[i];
  918. String desc = m.signature;
  919. desc = desc.replace('/', '.');
  920. data.writeUTF(m.member.getName());
  921. data.writeInt(m.member.getModifiers());
  922. data.writeUTF(desc);
  923. }
  924. /* Compute the hash value for this class.
  925. * Use only the first 64 bits of the hash.
  926. */
  927. data.flush();
  928. byte hasharray[] = md.digest();
  929. for (int i = 0; i < Math.min(8, hasharray.length); i++) {
  930. h += (long)(hasharray[i] & 255) << (i * 8);
  931. }
  932. } catch (IOException ignore) {
  933. /* can't happen, but be deterministic anyway. */
  934. h = -1;
  935. } catch (NoSuchAlgorithmException complain) {
  936. throw new SecurityException(complain.getMessage());
  937. }
  938. return h;
  939. }
  940. private static long computeStructuralUID(com.sun.corba.se.internal.io.ObjectStreamClass osc, Class cl) {
  941. ByteArrayOutputStream devnull = new ByteArrayOutputStream(512);
  942. long h = 0;
  943. try {
  944. if ((!java.io.Serializable.class.isAssignableFrom(cl)) ||
  945. (cl.isInterface())){
  946. return 0;
  947. }
  948. if (java.io.Externalizable.class.isAssignableFrom(cl)) {
  949. return 1;
  950. }
  951. MessageDigest md = MessageDigest.getInstance("SHA");
  952. DigestOutputStream mdo = new DigestOutputStream(devnull, md);
  953. DataOutputStream data = new DataOutputStream(mdo);
  954. // Get SUID of parent
  955. Class parent = cl.getSuperclass();
  956. if ((parent != null))
  957. // SerialBug 1; acc. to spec the one for
  958. // java.lang.object
  959. // should be computed and put
  960. // && (parent != java.lang.Object.class))
  961. {
  962. //data.writeLong(computeSerialVersionUID(null,parent));
  963. data.writeLong(computeStructuralUID(lookup(parent), parent));
  964. }
  965. if (osc.hasWriteObject())
  966. data.writeInt(2);
  967. else
  968. data.writeInt(1);
  969. // CORBA formal 00-11-03 10.6.2: For each field of the
  970. // class that is mapped to IDL, sorted lexicographically
  971. // by Java field name, in increasing order...
  972. ObjectStreamField[] field = osc.getFields();
  973. if (field.length > 1) {
  974. Arrays.sort(field, compareObjStrFieldsByName);
  975. }
  976. // ...Java field name in UTF encoding, field
  977. // descriptor, as defined by the JVM spec...
  978. for (int i = 0; i < field.length; i++) {
  979. data.writeUTF(field[i].getName());
  980. data.writeUTF(field[i].getSignature());
  981. }
  982. /* Compute the hash value for this class.
  983. * Use only the first 64 bits of the hash.
  984. */
  985. data.flush();
  986. byte hasharray[] = md.digest();
  987. // int minimum = Math.min(8, hasharray.length);
  988. // SerialBug 3: SHA computation is wrong; for loop reversed
  989. //for (int i = minimum; i > 0; i--)
  990. for (int i = 0; i < Math.min(8, hasharray.length); i++) {
  991. h += (long)(hasharray[i] & 255) << (i * 8);
  992. }
  993. } catch (IOException ignore) {
  994. /* can't happen, but be deterministic anyway. */
  995. h = -1;
  996. } catch (NoSuchAlgorithmException complain) {
  997. throw new SecurityException(complain.getMessage());
  998. }
  999. return h;
  1000. }
  1001. /**
  1002. * Compute the JVM signature for the class.
  1003. */
  1004. static String getSignature(Class clazz) {
  1005. String type = null;
  1006. if (clazz.isArray()) {
  1007. Class cl = clazz;
  1008. int dimensions = 0;
  1009. while (cl.isArray()) {
  1010. dimensions++;
  1011. cl = cl.getComponentType();
  1012. }
  1013. StringBuffer sb = new StringBuffer();
  1014. for (int i = 0; i < dimensions; i++) {
  1015. sb.append("[");
  1016. }
  1017. sb.append(getSignature(cl));
  1018. type = sb.toString();
  1019. } else if (clazz.isPrimitive()) {
  1020. if (clazz == Integer.TYPE) {
  1021. type = "I";
  1022. } else if (clazz == Byte.TYPE) {
  1023. type = "B";
  1024. } else if (clazz == Long.TYPE) {
  1025. type = "J";
  1026. } else if (clazz == Float.TYPE) {
  1027. type = "F";
  1028. } else if (clazz == Double.TYPE) {
  1029. type = "D";
  1030. } else if (clazz == Short.TYPE) {
  1031. type = "S";
  1032. } else if (clazz == Character.TYPE) {
  1033. type = "C";
  1034. } else if (clazz == Boolean.TYPE) {
  1035. type = "Z";
  1036. } else if (clazz == Void.TYPE) {
  1037. type = "V";
  1038. }
  1039. } else {
  1040. type = "L" + clazz.getName().replace('.', '/') + ";";
  1041. }
  1042. return type;
  1043. }
  1044. /*
  1045. * Compute the JVM method descriptor for the method.
  1046. */
  1047. static String getSignature(Method meth) {
  1048. StringBuffer sb = new StringBuffer();
  1049. sb.append("(");
  1050. Class[] params = meth.getParameterTypes(); // avoid clone
  1051. for (int j = 0; j < params.length; j++) {
  1052. sb.append(getSignature(params[j]));
  1053. }
  1054. sb.append(")");
  1055. sb.append(getSignature(meth.getReturnType()));
  1056. return sb.toString();
  1057. }
  1058. /*
  1059. * Compute the JVM constructor descriptor for the constructor.
  1060. */
  1061. static String getSignature(Constructor cons) {
  1062. StringBuffer sb = new StringBuffer();
  1063. sb.append("(");
  1064. Class[] params = cons.getParameterTypes(); // avoid clone
  1065. for (int j = 0; j < params.length; j++) {
  1066. sb.append(getSignature(params[j]));
  1067. }
  1068. sb.append(")V");
  1069. return sb.toString();
  1070. }
  1071. /*
  1072. * Cache of Class -> ClassDescriptor Mappings.
  1073. */
  1074. static private ObjectStreamClassEntry[] descriptorFor = new ObjectStreamClassEntry[61];
  1075. /*
  1076. * findDescriptorFor a Class. This looks in the cache for a
  1077. * mapping from Class -> ObjectStreamClass mappings. The hashCode
  1078. * of the Class is used for the lookup since the Class is the key.
  1079. * The entries are extended from java.lang.ref.SoftReference so the
  1080. * gc will be able to free them if needed.
  1081. */
  1082. private static ObjectStreamClass findDescriptorFor(Class cl) {
  1083. int hash = cl.hashCode();
  1084. int index = (hash & 0x7FFFFFFF) % descriptorFor.length;
  1085. ObjectStreamClassEntry e;
  1086. ObjectStreamClassEntry prev;
  1087. /* Free any initial entries whose refs have been cleared */
  1088. while ((e = descriptorFor[index]) != null && e.get() == null) {
  1089. descriptorFor[index] = e.next;
  1090. }
  1091. /* Traverse the chain looking for a descriptor with ofClass == cl.
  1092. * unlink entries that are unresolved.
  1093. */
  1094. prev = e;
  1095. while (e != null ) {
  1096. ObjectStreamClass desc = (ObjectStreamClass)(e.get());
  1097. if (desc == null) {
  1098. // This entry has been cleared, unlink it
  1099. prev.next = e.next;
  1100. } else {
  1101. if (desc.ofClass == cl)
  1102. return desc;
  1103. prev = e;
  1104. }
  1105. e = e.next;
  1106. }
  1107. return null;
  1108. }
  1109. /*
  1110. * insertDescriptorFor a Class -> ObjectStreamClass mapping.
  1111. */
  1112. private static void insertDescriptorFor(ObjectStreamClass desc) {
  1113. // Make sure not already present
  1114. if (findDescriptorFor(desc.ofClass) != null) {
  1115. return;
  1116. }
  1117. int hash = desc.ofClass.hashCode();
  1118. int index = (hash & 0x7FFFFFFF) % descriptorFor.length;
  1119. ObjectStreamClassEntry e = new ObjectStreamClassEntry(desc);
  1120. e.next = descriptorFor[index];
  1121. descriptorFor[index] = e;
  1122. }
  1123. private static Field[] getDeclaredFields(final Class clz) {
  1124. return (Field[]) AccessController.doPrivileged(new PrivilegedAction() {
  1125. public Object run() {
  1126. return clz.getDeclaredFields();
  1127. }
  1128. });
  1129. }
  1130. /*
  1131. * The name of this descriptor
  1132. */
  1133. private String name;
  1134. /*
  1135. * The descriptor of the supertype.
  1136. */
  1137. private ObjectStreamClass superclass;
  1138. /*
  1139. * Flags for Serializable and Externalizable.
  1140. */
  1141. private boolean serializable;
  1142. private boolean externalizable;
  1143. /*
  1144. * Array of persistent fields of this class, sorted by
  1145. * type and name.
  1146. */
  1147. private ObjectStreamField[] fields;
  1148. /*
  1149. * Class that is a descriptor for in this virtual machine.
  1150. */
  1151. private Class ofClass;
  1152. /*
  1153. * True if descriptor for a proxy class.
  1154. */
  1155. boolean forProxyClass;
  1156. /*
  1157. * SerialVersionUID for this class.
  1158. */
  1159. private long suid = kDefaultUID;
  1160. private String suidStr = null;
  1161. /*
  1162. * Actual (computed) SerialVersionUID for this class.
  1163. */
  1164. private long actualSuid = kDefaultUID;
  1165. private String actualSuidStr = null;
  1166. /*
  1167. * The total number of bytes of primitive fields.
  1168. * The total number of object fields.
  1169. */
  1170. int primBytes;
  1171. int objFields;
  1172. /**
  1173. * Flag indicating whether or not this instance has
  1174. * successfully completed initialization. This is to
  1175. * try to fix bug 4373844. Working to move to
  1176. * reusing java.io.ObjectStreamClass for JDK 1.5.
  1177. */
  1178. private boolean initialized = false;
  1179. /* Internal lock object. */
  1180. private Object lock = new Object();
  1181. /* True if this class has/had a writeObject method */
  1182. private boolean hasWriteObjectMethod;
  1183. /* In JDK 1.1, external data was not written in block mode.
  1184. * As of JDK 1.2, external data is written in block data mode. This
  1185. * flag enables JDK 1.2 to be able to read JDK 1.1 written external data.
  1186. *
  1187. * @since JDK 1.2
  1188. */
  1189. private boolean hasExternalizableBlockData;
  1190. Method writeObjectMethod;
  1191. Method readObjectMethod;
  1192. private Method writeReplaceObjectMethod;
  1193. private Method readResolveObjectMethod;
  1194. /*
  1195. * ObjectStreamClass that this one was built from.
  1196. */
  1197. private ObjectStreamClass localClassDesc;
  1198. /* Find out if the class has a static class initializer <clinit> */
  1199. private static native boolean hasStaticInitializer(Class cl);
  1200. /* Get the private static final field for serial version UID */
  1201. // private static native long getSerialVersionUIDField(Class cl);
  1202. /* The Class Object for java.io.Serializable */
  1203. private static Class classSerializable = null;
  1204. private static Class classExternalizable = null;
  1205. /*
  1206. * Resolve java.io.Serializable at load time.
  1207. */
  1208. static {
  1209. try {
  1210. classSerializable = Class.forName("java.io.Serializable");
  1211. classExternalizable = Class.forName("java.io.Externalizable");
  1212. } catch (Throwable e) {
  1213. System.err.println("Could not load java.io.Serializable or java.io.Externalizable.");
  1214. }
  1215. }
  1216. /** use serialVersionUID from JDK 1.1. for interoperability */
  1217. private static final long serialVersionUID = -6120832682080437368L;
  1218. /**
  1219. * Set serialPersistentFields of a Serializable class to this value to
  1220. * denote that the class has no Serializable fields.
  1221. */
  1222. public static final ObjectStreamField[] NO_FIELDS =
  1223. new ObjectStreamField[0];
  1224. /*
  1225. * Entries held in the Cache of known ObjectStreamClass objects.
  1226. * Entries are chained together with the same hash value (modulo array size).
  1227. */
  1228. private static class ObjectStreamClassEntry // extends java.lang.ref.SoftReference
  1229. {
  1230. ObjectStreamClassEntry(ObjectStreamClass c) {
  1231. //super(c);
  1232. this.c = c;
  1233. }
  1234. ObjectStreamClassEntry next;
  1235. public Object get()
  1236. {
  1237. return c;
  1238. }
  1239. private ObjectStreamClass c;
  1240. }
  1241. /*
  1242. * Comparator object for Classes and Interfaces
  1243. */
  1244. private static Comparator compareClassByName =
  1245. new CompareClassByName();
  1246. private static class CompareClassByName implements Comparator {
  1247. public int compare(Object o1, Object o2) {
  1248. Class c1 = (Class)o1;
  1249. Class c2 = (Class)o2;
  1250. return (c1.getName()).compareTo(c2.getName());
  1251. }
  1252. }
  1253. /**
  1254. * Comparator for ObjectStreamFields by name
  1255. */
  1256. private final static Comparator compareObjStrFieldsByName
  1257. = new CompareObjStrFieldsByName();
  1258. private static class CompareObjStrFieldsByName implements Comparator {
  1259. public int compare(Object o1, Object o2) {
  1260. ObjectStreamField osf1 = (ObjectStreamField)o1;
  1261. ObjectStreamField osf2 = (ObjectStreamField)o2;
  1262. return osf1.getName().compareTo(osf2.getName());
  1263. }
  1264. }
  1265. /*
  1266. * Comparator object for Members, Fields, and Methods
  1267. */
  1268. private static Comparator compareMemberByName =
  1269. new CompareMemberByName();
  1270. private static class CompareMemberByName implements Comparator {
  1271. public int compare(Object o1, Object o2) {
  1272. String s1 = ((Member)o1).getName();
  1273. String s2 = ((Member)o2).getName();
  1274. if (o1 instanceof Method) {
  1275. s1 += getSignature((Method)o1);
  1276. s2 += getSignature((Method)o2);
  1277. } else if (o1 instanceof Constructor) {
  1278. s1 += getSignature((Constructor)o1);
  1279. s2 += getSignature((Constructor)o2);
  1280. }
  1281. return s1.compareTo(s2);
  1282. }
  1283. }
  1284. /* It is expensive to recompute a method or constructor signature
  1285. many times, so compute it only once using this data structure. */
  1286. private static class MethodSignature implements Comparator {
  1287. Member member;
  1288. String signature; // cached parameter signature
  1289. /* Given an array of Method or Constructor members,
  1290. return a sorted array of the non-private members.*/
  1291. /* A better implementation would be to implement the returned data
  1292. structure as an insertion sorted link list.*/
  1293. static MethodSignature[] removePrivateAndSort(Member[] m) {
  1294. int numNonPrivate = 0;
  1295. for (int i = 0; i < m.length; i++) {
  1296. if (! Modifier.isPrivate(m[i].getModifiers())) {
  1297. numNonPrivate++;
  1298. }
  1299. }
  1300. MethodSignature[] cm = new MethodSignature[numNonPrivate];
  1301. int cmi = 0;
  1302. for (int i = 0; i < m.length; i++) {
  1303. if (! Modifier.isPrivate(m[i].getModifiers())) {
  1304. cm[cmi] = new MethodSignature(m[i]);
  1305. cmi++;
  1306. }
  1307. }
  1308. if (cmi > 0)
  1309. Arrays.sort(cm, cm[0]);
  1310. return cm;
  1311. }
  1312. /* Assumes that o1 and o2 are either both methods
  1313. or both constructors.*/
  1314. public int compare(Object o1, Object o2) {
  1315. /* Arrays.sort calls compare when o1 and o2 are equal.*/
  1316. if (o1 == o2)
  1317. return 0;
  1318. MethodSignature c1 = (MethodSignature)o1;
  1319. MethodSignature c2 = (MethodSignature)o2;
  1320. int result;
  1321. if (isConstructor()) {
  1322. result = c1.signature.compareTo(c2.signature);
  1323. } else { // is a Method.
  1324. result = c1.member.getName().compareTo(c2.member.getName());
  1325. if (result == 0)
  1326. result = c1.signature.compareTo(c2.signature);
  1327. }
  1328. return result;
  1329. }
  1330. final private boolean isConstructor() {
  1331. return member instanceof Constructor;
  1332. }
  1333. private MethodSignature(Member m) {
  1334. member = m;
  1335. if (isConstructor()) {
  1336. signature = ObjectStreamClass.getSignature((Constructor)m);
  1337. } else {
  1338. signature = ObjectStreamClass.getSignature((Method)m);
  1339. }
  1340. }
  1341. }
  1342. /**
  1343. * Returns non-static, non-abstract method with given signature provided it
  1344. * is defined by or accessible (via inheritance) by the given class, or
  1345. * null if no match found. Access checks are disabled on the returned
  1346. * method (if any).
  1347. *
  1348. * Copied from the Merlin java.io.ObjectStreamClass.
  1349. */
  1350. private static Method getInheritableMethod(Class cl, String name,
  1351. Class[] argTypes,
  1352. Class returnType)
  1353. {
  1354. Method meth = null;
  1355. Class defCl = cl;
  1356. while (defCl != null) {
  1357. try {
  1358. meth = defCl.getDeclaredMethod(name, argTypes);
  1359. break;
  1360. } catch (NoSuchMethodException ex) {
  1361. defCl = defCl.getSuperclass();
  1362. }
  1363. }
  1364. if ((meth == null) || (meth.getReturnType() != returnType)) {
  1365. return null;
  1366. }
  1367. meth.setAccessible(true);
  1368. int mods = meth.getModifiers();
  1369. if ((mods & (Modifier.STATIC | Modifier.ABSTRACT)) != 0) {
  1370. return null;
  1371. } else if ((mods & (Modifier.PUBLIC | Modifier.PROTECTED)) != 0) {
  1372. return meth;
  1373. } else if ((mods & Modifier.PRIVATE) != 0) {
  1374. return (cl == defCl) ? meth : null;
  1375. } else {
  1376. return packageEquals(cl, defCl) ? meth : null;
  1377. }
  1378. }
  1379. /**
  1380. * Returns true if classes are defined in the same package, false
  1381. * otherwise.
  1382. *
  1383. * Copied from the Merlin java.io.ObjectStreamClass.
  1384. */
  1385. private static boolean packageEquals(Class cl1, Class cl2) {
  1386. Package pkg1 = cl1.getPackage(), pkg2 = cl2.getPackage();
  1387. return ((pkg1 == pkg2) || ((pkg1 != null) && (pkg1.equals(pkg2))));
  1388. }
  1389. }