ObjectOutputStream.java 46 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537
  1. /* ObjectOutputStream.java -- Class used to write serialized objects
  2. Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2008
  3. Free Software Foundation, Inc.
  4. This file is part of GNU Classpath.
  5. GNU Classpath is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2, or (at your option)
  8. any later version.
  9. GNU Classpath is distributed in the hope that it will be useful, but
  10. WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with GNU Classpath; see the file COPYING. If not, write to the
  15. Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  16. 02110-1301 USA.
  17. Linking this library statically or dynamically with other modules is
  18. making a combined work based on this library. Thus, the terms and
  19. conditions of the GNU General Public License cover the whole
  20. combination.
  21. As a special exception, the copyright holders of this library give you
  22. permission to link this library with independent modules to produce an
  23. executable, regardless of the license terms of these independent
  24. modules, and to copy and distribute the resulting executable under
  25. terms of your choice, provided that you also meet, for each linked
  26. independent module, the terms and conditions of the license of that
  27. module. An independent module is a module which is not derived from
  28. or based on this library. If you modify this library, you may extend
  29. this exception to your version of the library, but you are not
  30. obligated to do so. If you do not wish to do so, delete this
  31. exception statement from your version. */
  32. package java.io;
  33. import gnu.java.io.ObjectIdentityMap2Int;
  34. import gnu.java.lang.reflect.TypeSignature;
  35. import gnu.java.security.action.SetAccessibleAction;
  36. import java.lang.reflect.Array;
  37. import java.lang.reflect.Field;
  38. import java.lang.reflect.InvocationTargetException;
  39. import java.lang.reflect.Method;
  40. import java.security.AccessController;
  41. import java.security.PrivilegedAction;
  42. /**
  43. * An <code>ObjectOutputStream</code> can be used to write objects
  44. * as well as primitive data in a platform-independent manner to an
  45. * <code>OutputStream</code>.
  46. *
  47. * The data produced by an <code>ObjectOutputStream</code> can be read
  48. * and reconstituted by an <code>ObjectInputStream</code>.
  49. *
  50. * <code>writeObject (Object)</code> is used to write Objects, the
  51. * <code>write&lt;type&gt;</code> methods are used to write primitive
  52. * data (as in <code>DataOutputStream</code>). Strings can be written
  53. * as objects or as primitive data.
  54. *
  55. * Not all objects can be written out using an
  56. * <code>ObjectOutputStream</code>. Only those objects that are an
  57. * instance of <code>java.io.Serializable</code> can be written.
  58. *
  59. * Using default serialization, information about the class of an
  60. * object is written, all of the non-transient, non-static fields of
  61. * the object are written, if any of these fields are objects, they are
  62. * written out in the same manner.
  63. *
  64. * An object is only written out the first time it is encountered. If
  65. * the object is encountered later, a reference to it is written to
  66. * the underlying stream. Thus writing circular object graphs
  67. * does not present a problem, nor are relationships between objects
  68. * in a graph lost.
  69. *
  70. * Example usage:
  71. * <pre>
  72. * Hashtable map = new Hashtable ();
  73. * map.put ("one", new Integer (1));
  74. * map.put ("two", new Integer (2));
  75. *
  76. * ObjectOutputStream oos =
  77. * new ObjectOutputStream (new FileOutputStream ("numbers"));
  78. * oos.writeObject (map);
  79. * oos.close ();
  80. *
  81. * ObjectInputStream ois =
  82. * new ObjectInputStream (new FileInputStream ("numbers"));
  83. * Hashtable newmap = (Hashtable)ois.readObject ();
  84. *
  85. * System.out.println (newmap);
  86. * </pre>
  87. *
  88. * The default serialization can be overriden in two ways.
  89. *
  90. * By defining a method <code>private void
  91. * writeObject (ObjectOutputStream)</code>, a class can dictate exactly
  92. * how information about itself is written.
  93. * <code>defaultWriteObject ()</code> may be called from this method to
  94. * carry out default serialization. This method is not
  95. * responsible for dealing with fields of super-classes or subclasses.
  96. *
  97. * By implementing <code>java.io.Externalizable</code>. This gives
  98. * the class complete control over the way it is written to the
  99. * stream. If this approach is used the burden of writing superclass
  100. * and subclass data is transfered to the class implementing
  101. * <code>java.io.Externalizable</code>.
  102. *
  103. * @see java.io.DataOutputStream
  104. * @see java.io.Externalizable
  105. * @see java.io.ObjectInputStream
  106. * @see java.io.Serializable
  107. * @author Tom Tromey (tromey@redhat.com)
  108. * @author Jeroen Frijters (jeroen@frijters.net)
  109. * @author Guilhem Lavaux (guilhem@kaffe.org)
  110. * @author Michael Koch (konqueror@gmx.de)
  111. * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
  112. */
  113. public class ObjectOutputStream extends OutputStream
  114. implements ObjectOutput, ObjectStreamConstants
  115. {
  116. /**
  117. * Creates a new <code>ObjectOutputStream</code> that will do all of
  118. * its writing onto <code>out</code>. This method also initializes
  119. * the stream by writing the header information (stream magic number
  120. * and stream version).
  121. *
  122. * @exception IOException Writing stream header to underlying
  123. * stream cannot be completed.
  124. *
  125. * @see #writeStreamHeader()
  126. */
  127. public ObjectOutputStream (OutputStream out) throws IOException
  128. {
  129. SecurityManager secMan = System.getSecurityManager();
  130. if (secMan != null && overridesMethods(getClass()))
  131. secMan.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
  132. realOutput = new DataOutputStream(out);
  133. blockData = new byte[ BUFFER_SIZE ];
  134. blockDataCount = 0;
  135. blockDataOutput = new DataOutputStream(this);
  136. setBlockDataMode(true);
  137. replacementEnabled = false;
  138. isSerializing = false;
  139. nextOID = baseWireHandle;
  140. OIDLookupTable = new ObjectIdentityMap2Int();
  141. protocolVersion = defaultProtocolVersion;
  142. useSubclassMethod = false;
  143. writeStreamHeader();
  144. if (DEBUG)
  145. {
  146. String val = System.getProperty("gcj.dumpobjects");
  147. if (val != null && !val.equals(""))
  148. dump = true;
  149. }
  150. }
  151. /**
  152. * Writes a representation of <code>obj</code> to the underlying
  153. * output stream by writing out information about its class, then
  154. * writing out each of the objects non-transient, non-static
  155. * fields. If any of these fields are other objects,
  156. * they are written out in the same manner.
  157. *
  158. * This method can be overriden by a class by implementing
  159. * <code>private void writeObject (ObjectOutputStream)</code>.
  160. *
  161. * If an exception is thrown from this method, the stream is left in
  162. * an undefined state.
  163. *
  164. * @param obj the object to serialize.
  165. * @exception NotSerializableException An attempt was made to
  166. * serialize an <code>Object</code> that is not serializable.
  167. *
  168. * @exception InvalidClassException Somebody tried to serialize
  169. * an object which is wrongly formatted.
  170. *
  171. * @exception IOException Exception from underlying
  172. * <code>OutputStream</code>.
  173. * @see #writeUnshared(Object)
  174. */
  175. public final void writeObject(Object obj) throws IOException
  176. {
  177. writeObject(obj, true);
  178. }
  179. /**
  180. * Writes an object to the stream in the same manner as
  181. * {@link #writeObject(Object)}, but without the use of
  182. * references. As a result, the object is always written
  183. * to the stream in full. Likewise, if an object is written
  184. * by this method and is then later written again by
  185. * {@link #writeObject(Object)}, both calls will write out
  186. * the object in full, as the later call to
  187. * {@link #writeObject(Object)} will know nothing of the
  188. * earlier use of {@link #writeUnshared(Object)}.
  189. *
  190. * @param obj the object to serialize.
  191. * @throws NotSerializableException if the object being
  192. * serialized does not implement
  193. * {@link Serializable}.
  194. * @throws InvalidClassException if a problem occurs with
  195. * the class of the object being
  196. * serialized.
  197. * @throws IOException if an I/O error occurs on the underlying
  198. * <code>OutputStream</code>.
  199. * @since 1.4
  200. * @see #writeObject(Object)
  201. */
  202. public void writeUnshared(Object obj)
  203. throws IOException
  204. {
  205. writeObject(obj, false);
  206. }
  207. /**
  208. * Writes a representation of <code>obj</code> to the underlying
  209. * output stream by writing out information about its class, then
  210. * writing out each of the objects non-transient, non-static
  211. * fields. If any of these fields are other objects,
  212. * they are written out in the same manner.
  213. *
  214. * This method can be overriden by a class by implementing
  215. * <code>private void writeObject (ObjectOutputStream)</code>.
  216. *
  217. * If an exception is thrown from this method, the stream is left in
  218. * an undefined state.
  219. *
  220. * @param obj the object to serialize.
  221. * @param shared true if the serialized object should be
  222. * shared with later calls.
  223. * @exception NotSerializableException An attempt was made to
  224. * serialize an <code>Object</code> that is not serializable.
  225. *
  226. * @exception InvalidClassException Somebody tried to serialize
  227. * an object which is wrongly formatted.
  228. *
  229. * @exception IOException Exception from underlying
  230. * <code>OutputStream</code>.
  231. * @see #writeUnshared(Object)
  232. */
  233. private final void writeObject(Object obj, boolean shared)
  234. throws IOException
  235. {
  236. if (useSubclassMethod)
  237. {
  238. if (dump)
  239. dumpElementln ("WRITE OVERRIDE: " + obj);
  240. writeObjectOverride(obj);
  241. return;
  242. }
  243. if (dump)
  244. dumpElementln ("WRITE: ", obj);
  245. depth += 2;
  246. boolean was_serializing = isSerializing;
  247. boolean old_mode = setBlockDataMode(false);
  248. try
  249. {
  250. isSerializing = true;
  251. boolean replaceDone = false;
  252. Object replacedObject = null;
  253. while (true)
  254. {
  255. if (obj == null)
  256. {
  257. realOutput.writeByte(TC_NULL);
  258. break;
  259. }
  260. int handle = findHandle(obj);
  261. if (handle >= 0 && shared)
  262. {
  263. realOutput.writeByte(TC_REFERENCE);
  264. realOutput.writeInt(handle);
  265. break;
  266. }
  267. if (obj instanceof Class)
  268. {
  269. Class cl = (Class)obj;
  270. ObjectStreamClass osc = ObjectStreamClass.lookupForClassObject(cl);
  271. realOutput.writeByte(TC_CLASS);
  272. if (!osc.isProxyClass)
  273. {
  274. writeObject (osc);
  275. }
  276. else
  277. {System.err.println("1");
  278. realOutput.writeByte(TC_PROXYCLASSDESC);
  279. Class[] intfs = cl.getInterfaces();
  280. realOutput.writeInt(intfs.length);
  281. for (int i = 0; i < intfs.length; i++)
  282. realOutput.writeUTF(intfs[i].getName());
  283. boolean oldmode = setBlockDataMode(true);
  284. annotateProxyClass(cl);
  285. setBlockDataMode(oldmode);
  286. realOutput.writeByte(TC_ENDBLOCKDATA);
  287. writeObject(osc.getSuper());
  288. }
  289. if (shared)
  290. assignNewHandle(obj);
  291. break;
  292. }
  293. if (obj instanceof ObjectStreamClass)
  294. {
  295. writeClassDescriptor((ObjectStreamClass) obj);
  296. break;
  297. }
  298. Class clazz = obj.getClass();
  299. ObjectStreamClass osc = ObjectStreamClass.lookupForClassObject(clazz);
  300. if (osc == null)
  301. throw new NotSerializableException(clazz.getName());
  302. if (osc.isEnum())
  303. {
  304. /* TC_ENUM classDesc newHandle enumConstantName */
  305. realOutput.writeByte(TC_ENUM);
  306. writeObject(osc);
  307. if (shared)
  308. assignNewHandle(obj);
  309. writeObject(((Enum) obj).name());
  310. break;
  311. }
  312. if ((replacementEnabled || obj instanceof Serializable)
  313. && ! replaceDone)
  314. {
  315. replacedObject = obj;
  316. if (obj instanceof Serializable)
  317. {
  318. try
  319. {
  320. Method m = osc.writeReplaceMethod;
  321. if (m != null)
  322. obj = m.invoke(obj, new Object[0]);
  323. }
  324. catch (IllegalAccessException ignore)
  325. {
  326. }
  327. catch (InvocationTargetException ignore)
  328. {
  329. }
  330. }
  331. if (replacementEnabled)
  332. obj = replaceObject(obj);
  333. replaceDone = true;
  334. continue;
  335. }
  336. if (obj instanceof String)
  337. {
  338. String s = (String)obj;
  339. long l = realOutput.getUTFlength(s, 0, 0);
  340. if (l <= 65535)
  341. {
  342. realOutput.writeByte(TC_STRING);
  343. if (shared)
  344. assignNewHandle(obj);
  345. realOutput.writeUTFShort(s, (int)l);
  346. }
  347. else
  348. {
  349. realOutput.writeByte(TC_LONGSTRING);
  350. if (shared)
  351. assignNewHandle(obj);
  352. realOutput.writeUTFLong(s, l);
  353. }
  354. break;
  355. }
  356. if (clazz.isArray ())
  357. {
  358. realOutput.writeByte(TC_ARRAY);
  359. writeObject(osc);
  360. if (shared)
  361. assignNewHandle(obj);
  362. writeArraySizeAndElements(obj, clazz.getComponentType());
  363. break;
  364. }
  365. realOutput.writeByte(TC_OBJECT);
  366. writeObject(osc);
  367. if (shared)
  368. if (replaceDone)
  369. assignNewHandle(replacedObject);
  370. else
  371. assignNewHandle(obj);
  372. if (obj instanceof Externalizable)
  373. {
  374. if (protocolVersion == PROTOCOL_VERSION_2)
  375. setBlockDataMode(true);
  376. ((Externalizable)obj).writeExternal(this);
  377. if (protocolVersion == PROTOCOL_VERSION_2)
  378. {
  379. setBlockDataMode(false);
  380. realOutput.writeByte(TC_ENDBLOCKDATA);
  381. }
  382. break;
  383. }
  384. if (obj instanceof Serializable)
  385. {
  386. Object prevObject = this.currentObject;
  387. ObjectStreamClass prevObjectStreamClass = this.currentObjectStreamClass;
  388. currentObject = obj;
  389. ObjectStreamClass[] hierarchy = osc.hierarchy();
  390. for (int i = 0; i < hierarchy.length; i++)
  391. {
  392. currentObjectStreamClass = hierarchy[i];
  393. fieldsAlreadyWritten = false;
  394. if (currentObjectStreamClass.hasWriteMethod())
  395. {
  396. if (dump)
  397. dumpElementln ("WRITE METHOD CALLED FOR: ", obj);
  398. setBlockDataMode(true);
  399. callWriteMethod(obj, currentObjectStreamClass);
  400. setBlockDataMode(false);
  401. realOutput.writeByte(TC_ENDBLOCKDATA);
  402. if (dump)
  403. dumpElementln ("WRITE ENDBLOCKDATA FOR: ", obj);
  404. }
  405. else
  406. {
  407. if (dump)
  408. dumpElementln ("WRITE FIELDS CALLED FOR: ", obj);
  409. writeFields(obj, currentObjectStreamClass);
  410. }
  411. }
  412. this.currentObject = prevObject;
  413. this.currentObjectStreamClass = prevObjectStreamClass;
  414. currentPutField = null;
  415. break;
  416. }
  417. throw new NotSerializableException(clazz.getName()
  418. + " in "
  419. + obj.getClass());
  420. } // end pseudo-loop
  421. }
  422. catch (ObjectStreamException ose)
  423. {
  424. // Rethrow these are fatal.
  425. throw ose;
  426. }
  427. catch (IOException e)
  428. {
  429. realOutput.writeByte(TC_EXCEPTION);
  430. reset(true);
  431. setBlockDataMode(false);
  432. try
  433. {
  434. if (DEBUG)
  435. {
  436. e.printStackTrace(System.out);
  437. }
  438. writeObject(e);
  439. }
  440. catch (IOException ioe)
  441. {
  442. StreamCorruptedException ex =
  443. new StreamCorruptedException
  444. (ioe + " thrown while exception was being written to stream.");
  445. if (DEBUG)
  446. {
  447. ex.printStackTrace(System.out);
  448. }
  449. throw ex;
  450. }
  451. reset (true);
  452. }
  453. finally
  454. {
  455. isSerializing = was_serializing;
  456. setBlockDataMode(old_mode);
  457. depth -= 2;
  458. if (dump)
  459. dumpElementln ("END: ", obj);
  460. }
  461. }
  462. protected void writeClassDescriptor(ObjectStreamClass osc) throws IOException
  463. {
  464. if (osc.isProxyClass)
  465. {
  466. realOutput.writeByte(TC_PROXYCLASSDESC);
  467. Class[] intfs = osc.forClass().getInterfaces();
  468. realOutput.writeInt(intfs.length);
  469. for (int i = 0; i < intfs.length; i++)
  470. realOutput.writeUTF(intfs[i].getName());
  471. assignNewHandle(osc);
  472. boolean oldmode = setBlockDataMode(true);
  473. annotateProxyClass(osc.forClass());
  474. setBlockDataMode(oldmode);
  475. realOutput.writeByte(TC_ENDBLOCKDATA);
  476. }
  477. else
  478. {
  479. realOutput.writeByte(TC_CLASSDESC);
  480. realOutput.writeUTF(osc.getName());
  481. if (osc.isEnum())
  482. realOutput.writeLong(0L);
  483. else
  484. realOutput.writeLong(osc.getSerialVersionUID());
  485. assignNewHandle(osc);
  486. int flags = osc.getFlags();
  487. if (protocolVersion == PROTOCOL_VERSION_2
  488. && osc.isExternalizable())
  489. flags |= SC_BLOCK_DATA;
  490. realOutput.writeByte(flags);
  491. ObjectStreamField[] fields = osc.fields;
  492. if (fields == ObjectStreamClass.INVALID_FIELDS)
  493. throw new InvalidClassException
  494. (osc.getName(), "serialPersistentFields is invalid");
  495. realOutput.writeShort(fields.length);
  496. ObjectStreamField field;
  497. for (int i = 0; i < fields.length; i++)
  498. {
  499. field = fields[i];
  500. realOutput.writeByte(field.getTypeCode ());
  501. realOutput.writeUTF(field.getName ());
  502. if (! field.isPrimitive())
  503. writeObject(field.getTypeString());
  504. }
  505. boolean oldmode = setBlockDataMode(true);
  506. annotateClass(osc.forClass());
  507. setBlockDataMode(oldmode);
  508. realOutput.writeByte(TC_ENDBLOCKDATA);
  509. }
  510. if (osc.isSerializable() || osc.isExternalizable())
  511. writeObject(osc.getSuper());
  512. else
  513. writeObject(null);
  514. }
  515. /**
  516. * Writes the current objects non-transient, non-static fields from
  517. * the current class to the underlying output stream.
  518. *
  519. * This method is intended to be called from within a object's
  520. * <code>private void writeObject (ObjectOutputStream)</code>
  521. * method.
  522. *
  523. * @exception NotActiveException This method was called from a
  524. * context other than from the current object's and current class's
  525. * <code>private void writeObject (ObjectOutputStream)</code>
  526. * method.
  527. *
  528. * @exception IOException Exception from underlying
  529. * <code>OutputStream</code>.
  530. */
  531. public void defaultWriteObject()
  532. throws IOException, NotActiveException
  533. {
  534. markFieldsWritten();
  535. writeFields(currentObject, currentObjectStreamClass);
  536. }
  537. private void markFieldsWritten() throws IOException
  538. {
  539. if (currentObject == null || currentObjectStreamClass == null)
  540. throw new NotActiveException
  541. ("defaultWriteObject called by non-active class and/or object");
  542. if (fieldsAlreadyWritten)
  543. throw new IOException
  544. ("Only one of writeFields and defaultWriteObject may be called, and it may only be called once");
  545. fieldsAlreadyWritten = true;
  546. }
  547. /**
  548. * Resets stream to state equivalent to the state just after it was
  549. * constructed.
  550. *
  551. * Causes all objects previously written to the stream to be
  552. * forgotten. A notification of this reset is also written to the
  553. * underlying stream.
  554. *
  555. * @exception IOException Exception from underlying
  556. * <code>OutputStream</code> or reset called while serialization is
  557. * in progress.
  558. */
  559. public void reset() throws IOException
  560. {
  561. reset(false);
  562. }
  563. private void reset(boolean internal) throws IOException
  564. {
  565. if (!internal)
  566. {
  567. if (isSerializing)
  568. throw new IOException("Reset called while serialization in progress");
  569. realOutput.writeByte(TC_RESET);
  570. }
  571. clearHandles();
  572. }
  573. /**
  574. * Informs this <code>ObjectOutputStream</code> to write data
  575. * according to the specified protocol. There are currently two
  576. * different protocols, specified by <code>PROTOCOL_VERSION_1</code>
  577. * and <code>PROTOCOL_VERSION_2</code>. This implementation writes
  578. * data using <code>PROTOCOL_VERSION_2</code> by default, as is done
  579. * since the JDK 1.2.
  580. * <p>
  581. * For an explanation of the differences between the two protocols
  582. * see the Java Object Serialization Specification.
  583. * </p>
  584. *
  585. * @param version the version to use.
  586. *
  587. * @throws IllegalArgumentException if <code>version</code> is not a valid
  588. * protocol.
  589. * @throws IllegalStateException if called after the first the first object
  590. * was serialized.
  591. * @throws IOException if an I/O error occurs.
  592. *
  593. * @see ObjectStreamConstants#PROTOCOL_VERSION_1
  594. * @see ObjectStreamConstants#PROTOCOL_VERSION_2
  595. *
  596. * @since 1.2
  597. */
  598. public void useProtocolVersion(int version) throws IOException
  599. {
  600. if (version != PROTOCOL_VERSION_1 && version != PROTOCOL_VERSION_2)
  601. throw new IllegalArgumentException("Invalid protocol version requested.");
  602. if (nextOID != baseWireHandle)
  603. throw new IllegalStateException("Protocol version cannot be changed "
  604. + "after serialization started.");
  605. protocolVersion = version;
  606. }
  607. /**
  608. * An empty hook that allows subclasses to write extra information
  609. * about classes to the stream. This method is called the first
  610. * time each class is seen, and after all of the standard
  611. * information about the class has been written.
  612. *
  613. * @exception IOException Exception from underlying
  614. * <code>OutputStream</code>.
  615. *
  616. * @see ObjectInputStream#resolveClass(java.io.ObjectStreamClass)
  617. */
  618. protected void annotateClass(Class<?> cl) throws IOException
  619. {
  620. }
  621. protected void annotateProxyClass(Class<?> cl) throws IOException
  622. {
  623. }
  624. /**
  625. * Allows subclasses to replace objects that are written to the
  626. * stream with other objects to be written in their place. This
  627. * method is called the first time each object is encountered
  628. * (modulo reseting of the stream).
  629. *
  630. * This method must be enabled before it will be called in the
  631. * serialization process.
  632. *
  633. * @exception IOException Exception from underlying
  634. * <code>OutputStream</code>.
  635. *
  636. * @see #enableReplaceObject(boolean)
  637. */
  638. protected Object replaceObject(Object obj) throws IOException
  639. {
  640. return obj;
  641. }
  642. /**
  643. * If <code>enable</code> is <code>true</code> and this object is
  644. * trusted, then <code>replaceObject (Object)</code> will be called
  645. * in subsequent calls to <code>writeObject (Object)</code>.
  646. * Otherwise, <code>replaceObject (Object)</code> will not be called.
  647. *
  648. * @exception SecurityException This class is not trusted.
  649. */
  650. protected boolean enableReplaceObject(boolean enable)
  651. throws SecurityException
  652. {
  653. if (enable)
  654. {
  655. SecurityManager sm = System.getSecurityManager();
  656. if (sm != null)
  657. sm.checkPermission(new SerializablePermission("enableSubstitution"));
  658. }
  659. boolean old_val = replacementEnabled;
  660. replacementEnabled = enable;
  661. return old_val;
  662. }
  663. /**
  664. * Writes stream magic and stream version information to the
  665. * underlying stream.
  666. *
  667. * @exception IOException Exception from underlying
  668. * <code>OutputStream</code>.
  669. */
  670. protected void writeStreamHeader() throws IOException
  671. {
  672. realOutput.writeShort(STREAM_MAGIC);
  673. realOutput.writeShort(STREAM_VERSION);
  674. }
  675. /**
  676. * Protected constructor that allows subclasses to override
  677. * serialization. This constructor should be called by subclasses
  678. * that wish to override <code>writeObject (Object)</code>. This
  679. * method does a security check <i>NOTE: currently not
  680. * implemented</i>, then sets a flag that informs
  681. * <code>writeObject (Object)</code> to call the subclasses
  682. * <code>writeObjectOverride (Object)</code> method.
  683. *
  684. * @see #writeObjectOverride(Object)
  685. */
  686. protected ObjectOutputStream() throws IOException, SecurityException
  687. {
  688. SecurityManager sec_man = System.getSecurityManager ();
  689. if (sec_man != null)
  690. sec_man.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
  691. useSubclassMethod = true;
  692. }
  693. /**
  694. * This method allows subclasses to override the default
  695. * serialization mechanism provided by
  696. * <code>ObjectOutputStream</code>. To make this method be used for
  697. * writing objects, subclasses must invoke the 0-argument
  698. * constructor on this class from there constructor.
  699. *
  700. * @see #ObjectOutputStream()
  701. *
  702. * @exception NotActiveException Subclass has arranged for this
  703. * method to be called, but did not implement this method.
  704. */
  705. protected void writeObjectOverride(Object obj) throws NotActiveException,
  706. IOException
  707. {
  708. throw new NotActiveException
  709. ("Subclass of ObjectOutputStream must implement writeObjectOverride");
  710. }
  711. /**
  712. * @see DataOutputStream#write(int)
  713. */
  714. public void write (int data) throws IOException
  715. {
  716. if (writeDataAsBlocks)
  717. {
  718. if (blockDataCount == BUFFER_SIZE)
  719. drain();
  720. blockData[ blockDataCount++ ] = (byte)data;
  721. }
  722. else
  723. realOutput.write(data);
  724. }
  725. /**
  726. * @see DataOutputStream#write(byte[])
  727. */
  728. public void write(byte[] b) throws IOException
  729. {
  730. write(b, 0, b.length);
  731. }
  732. /**
  733. * @see DataOutputStream#write(byte[],int,int)
  734. */
  735. public void write(byte[] b, int off, int len) throws IOException
  736. {
  737. if (writeDataAsBlocks)
  738. {
  739. if (len < 0)
  740. throw new IndexOutOfBoundsException();
  741. if (blockDataCount + len < BUFFER_SIZE)
  742. {
  743. System.arraycopy(b, off, blockData, blockDataCount, len);
  744. blockDataCount += len;
  745. }
  746. else
  747. {
  748. drain();
  749. writeBlockDataHeader(len);
  750. realOutput.write(b, off, len);
  751. }
  752. }
  753. else
  754. realOutput.write(b, off, len);
  755. }
  756. /**
  757. * @see DataOutputStream#flush()
  758. */
  759. public void flush () throws IOException
  760. {
  761. drain();
  762. realOutput.flush();
  763. }
  764. /**
  765. * Causes the block-data buffer to be written to the underlying
  766. * stream, but does not flush underlying stream.
  767. *
  768. * @exception IOException Exception from underlying
  769. * <code>OutputStream</code>.
  770. */
  771. protected void drain() throws IOException
  772. {
  773. if (blockDataCount == 0)
  774. return;
  775. if (writeDataAsBlocks)
  776. writeBlockDataHeader(blockDataCount);
  777. realOutput.write(blockData, 0, blockDataCount);
  778. blockDataCount = 0;
  779. }
  780. /**
  781. * @see java.io.DataOutputStream#close ()
  782. */
  783. public void close() throws IOException
  784. {
  785. flush();
  786. realOutput.close();
  787. }
  788. /**
  789. * @see java.io.DataOutputStream#writeBoolean (boolean)
  790. */
  791. public void writeBoolean(boolean data) throws IOException
  792. {
  793. blockDataOutput.writeBoolean(data);
  794. }
  795. /**
  796. * @see java.io.DataOutputStream#writeByte (int)
  797. */
  798. public void writeByte(int data) throws IOException
  799. {
  800. blockDataOutput.writeByte(data);
  801. }
  802. /**
  803. * @see java.io.DataOutputStream#writeShort (int)
  804. */
  805. public void writeShort (int data) throws IOException
  806. {
  807. blockDataOutput.writeShort(data);
  808. }
  809. /**
  810. * @see java.io.DataOutputStream#writeChar (int)
  811. */
  812. public void writeChar(int data) throws IOException
  813. {
  814. blockDataOutput.writeChar(data);
  815. }
  816. /**
  817. * @see java.io.DataOutputStream#writeInt (int)
  818. */
  819. public void writeInt(int data) throws IOException
  820. {
  821. blockDataOutput.writeInt(data);
  822. }
  823. /**
  824. * @see java.io.DataOutputStream#writeLong (long)
  825. */
  826. public void writeLong(long data) throws IOException
  827. {
  828. blockDataOutput.writeLong(data);
  829. }
  830. /**
  831. * @see java.io.DataOutputStream#writeFloat (float)
  832. */
  833. public void writeFloat(float data) throws IOException
  834. {
  835. blockDataOutput.writeFloat(data);
  836. }
  837. /**
  838. * @see java.io.DataOutputStream#writeDouble (double)
  839. */
  840. public void writeDouble(double data) throws IOException
  841. {
  842. blockDataOutput.writeDouble(data);
  843. }
  844. /**
  845. * @see java.io.DataOutputStream#writeBytes (java.lang.String)
  846. */
  847. public void writeBytes(String data) throws IOException
  848. {
  849. blockDataOutput.writeBytes(data);
  850. }
  851. /**
  852. * @see java.io.DataOutputStream#writeChars (java.lang.String)
  853. */
  854. public void writeChars(String data) throws IOException
  855. {
  856. dataOutput.writeChars(data);
  857. }
  858. /**
  859. * @see java.io.DataOutputStream#writeUTF (java.lang.String)
  860. */
  861. public void writeUTF(String data) throws IOException
  862. {
  863. dataOutput.writeUTF(data);
  864. }
  865. /**
  866. * This class allows a class to specify exactly which fields should
  867. * be written, and what values should be written for these fields.
  868. *
  869. * XXX: finish up comments
  870. */
  871. public abstract static class PutField
  872. {
  873. public abstract void put (String name, boolean value);
  874. public abstract void put (String name, byte value);
  875. public abstract void put (String name, char value);
  876. public abstract void put (String name, double value);
  877. public abstract void put (String name, float value);
  878. public abstract void put (String name, int value);
  879. public abstract void put (String name, long value);
  880. public abstract void put (String name, short value);
  881. public abstract void put (String name, Object value);
  882. /**
  883. * @deprecated
  884. */
  885. public abstract void write (ObjectOutput out) throws IOException;
  886. }
  887. public PutField putFields() throws IOException
  888. {
  889. if (currentPutField != null)
  890. return currentPutField;
  891. currentPutField = new PutField()
  892. {
  893. private byte[] prim_field_data
  894. = new byte[currentObjectStreamClass.primFieldSize];
  895. private Object[] objs
  896. = new Object[currentObjectStreamClass.objectFieldCount];
  897. private ObjectStreamField getField (String name)
  898. {
  899. ObjectStreamField field
  900. = currentObjectStreamClass.getField(name);
  901. if (field == null)
  902. throw new IllegalArgumentException("no such serializable field " + name);
  903. return field;
  904. }
  905. public void put(String name, boolean value)
  906. {
  907. ObjectStreamField field = getField(name);
  908. checkType(field, 'Z');
  909. prim_field_data[field.getOffset ()] = (byte)(value ? 1 : 0);
  910. }
  911. public void put(String name, byte value)
  912. {
  913. ObjectStreamField field = getField(name);
  914. checkType(field, 'B');
  915. prim_field_data[field.getOffset()] = value;
  916. }
  917. public void put(String name, char value)
  918. {
  919. ObjectStreamField field = getField(name);
  920. checkType(field, 'C');
  921. int off = field.getOffset();
  922. prim_field_data[off++] = (byte)(value >>> 8);
  923. prim_field_data[off] = (byte)value;
  924. }
  925. public void put(String name, double value)
  926. {
  927. ObjectStreamField field = getField (name);
  928. checkType(field, 'D');
  929. int off = field.getOffset();
  930. long l_value = Double.doubleToLongBits (value);
  931. prim_field_data[off++] = (byte)(l_value >>> 52);
  932. prim_field_data[off++] = (byte)(l_value >>> 48);
  933. prim_field_data[off++] = (byte)(l_value >>> 40);
  934. prim_field_data[off++] = (byte)(l_value >>> 32);
  935. prim_field_data[off++] = (byte)(l_value >>> 24);
  936. prim_field_data[off++] = (byte)(l_value >>> 16);
  937. prim_field_data[off++] = (byte)(l_value >>> 8);
  938. prim_field_data[off] = (byte)l_value;
  939. }
  940. public void put(String name, float value)
  941. {
  942. ObjectStreamField field = getField(name);
  943. checkType(field, 'F');
  944. int off = field.getOffset();
  945. int i_value = Float.floatToIntBits(value);
  946. prim_field_data[off++] = (byte)(i_value >>> 24);
  947. prim_field_data[off++] = (byte)(i_value >>> 16);
  948. prim_field_data[off++] = (byte)(i_value >>> 8);
  949. prim_field_data[off] = (byte)i_value;
  950. }
  951. public void put(String name, int value)
  952. {
  953. ObjectStreamField field = getField(name);
  954. checkType(field, 'I');
  955. int off = field.getOffset();
  956. prim_field_data[off++] = (byte)(value >>> 24);
  957. prim_field_data[off++] = (byte)(value >>> 16);
  958. prim_field_data[off++] = (byte)(value >>> 8);
  959. prim_field_data[off] = (byte)value;
  960. }
  961. public void put(String name, long value)
  962. {
  963. ObjectStreamField field = getField(name);
  964. checkType(field, 'J');
  965. int off = field.getOffset();
  966. prim_field_data[off++] = (byte)(value >>> 52);
  967. prim_field_data[off++] = (byte)(value >>> 48);
  968. prim_field_data[off++] = (byte)(value >>> 40);
  969. prim_field_data[off++] = (byte)(value >>> 32);
  970. prim_field_data[off++] = (byte)(value >>> 24);
  971. prim_field_data[off++] = (byte)(value >>> 16);
  972. prim_field_data[off++] = (byte)(value >>> 8);
  973. prim_field_data[off] = (byte)value;
  974. }
  975. public void put(String name, short value)
  976. {
  977. ObjectStreamField field = getField(name);
  978. checkType(field, 'S');
  979. int off = field.getOffset();
  980. prim_field_data[off++] = (byte)(value >>> 8);
  981. prim_field_data[off] = (byte)value;
  982. }
  983. public void put(String name, Object value)
  984. {
  985. ObjectStreamField field = getField(name);
  986. if (value != null &&
  987. ! field.getType().isAssignableFrom(value.getClass ()))
  988. throw new IllegalArgumentException("Class " + value.getClass() +
  989. " cannot be cast to " + field.getType());
  990. objs[field.getOffset()] = value;
  991. }
  992. public void write(ObjectOutput out) throws IOException
  993. {
  994. // Apparently Block data is not used with PutField as per
  995. // empirical evidence against JDK 1.2. Also see Mauve test
  996. // java.io.ObjectInputOutput.Test.GetPutField.
  997. boolean oldmode = setBlockDataMode(false);
  998. out.write(prim_field_data);
  999. for (int i = 0; i < objs.length; ++ i)
  1000. out.writeObject(objs[i]);
  1001. setBlockDataMode(oldmode);
  1002. }
  1003. private void checkType(ObjectStreamField field, char type)
  1004. throws IllegalArgumentException
  1005. {
  1006. if (TypeSignature.getEncodingOfClass(field.getType()).charAt(0)
  1007. != type)
  1008. throw new IllegalArgumentException();
  1009. }
  1010. };
  1011. // end PutFieldImpl
  1012. return currentPutField;
  1013. }
  1014. public void writeFields() throws IOException
  1015. {
  1016. if (currentPutField == null)
  1017. throw new NotActiveException("writeFields can only be called after putFields has been called");
  1018. markFieldsWritten();
  1019. currentPutField.write(this);
  1020. }
  1021. // write out the block-data buffer, picking the correct header
  1022. // depending on the size of the buffer
  1023. private void writeBlockDataHeader(int size) throws IOException
  1024. {
  1025. if (size < 256)
  1026. {
  1027. realOutput.writeByte(TC_BLOCKDATA);
  1028. realOutput.write(size);
  1029. }
  1030. else
  1031. {
  1032. realOutput.writeByte(TC_BLOCKDATALONG);
  1033. realOutput.writeInt(size);
  1034. }
  1035. }
  1036. // lookup the handle for OBJ, return null if OBJ doesn't have a
  1037. // handle yet
  1038. private int findHandle(Object obj)
  1039. {
  1040. return OIDLookupTable.get(obj);
  1041. }
  1042. // assigns the next availible handle to OBJ
  1043. private int assignNewHandle(Object obj)
  1044. {
  1045. OIDLookupTable.put(obj, nextOID);
  1046. return nextOID++;
  1047. }
  1048. // resets mapping from objects to handles
  1049. private void clearHandles()
  1050. {
  1051. nextOID = baseWireHandle;
  1052. OIDLookupTable.clear();
  1053. }
  1054. // write out array size followed by each element of the array
  1055. private void writeArraySizeAndElements(Object array, Class clazz)
  1056. throws IOException
  1057. {
  1058. int length = Array.getLength(array);
  1059. if (clazz.isPrimitive())
  1060. {
  1061. if (clazz == Boolean.TYPE)
  1062. {
  1063. boolean[] cast_array = (boolean[])array;
  1064. realOutput.writeInt (length);
  1065. for (int i = 0; i < length; i++)
  1066. realOutput.writeBoolean(cast_array[i]);
  1067. return;
  1068. }
  1069. if (clazz == Byte.TYPE)
  1070. {
  1071. byte[] cast_array = (byte[])array;
  1072. realOutput.writeInt(length);
  1073. realOutput.write(cast_array, 0, length);
  1074. return;
  1075. }
  1076. if (clazz == Character.TYPE)
  1077. {
  1078. char[] cast_array = (char[])array;
  1079. realOutput.writeInt(length);
  1080. for (int i = 0; i < length; i++)
  1081. realOutput.writeChar(cast_array[i]);
  1082. return;
  1083. }
  1084. if (clazz == Double.TYPE)
  1085. {
  1086. double[] cast_array = (double[])array;
  1087. realOutput.writeInt(length);
  1088. for (int i = 0; i < length; i++)
  1089. realOutput.writeDouble(cast_array[i]);
  1090. return;
  1091. }
  1092. if (clazz == Float.TYPE)
  1093. {
  1094. float[] cast_array = (float[])array;
  1095. realOutput.writeInt(length);
  1096. for (int i = 0; i < length; i++)
  1097. realOutput.writeFloat(cast_array[i]);
  1098. return;
  1099. }
  1100. if (clazz == Integer.TYPE)
  1101. {
  1102. int[] cast_array = (int[])array;
  1103. realOutput.writeInt(length);
  1104. for (int i = 0; i < length; i++)
  1105. realOutput.writeInt(cast_array[i]);
  1106. return;
  1107. }
  1108. if (clazz == Long.TYPE)
  1109. {
  1110. long[] cast_array = (long[])array;
  1111. realOutput.writeInt (length);
  1112. for (int i = 0; i < length; i++)
  1113. realOutput.writeLong(cast_array[i]);
  1114. return;
  1115. }
  1116. if (clazz == Short.TYPE)
  1117. {
  1118. short[] cast_array = (short[])array;
  1119. realOutput.writeInt (length);
  1120. for (int i = 0; i < length; i++)
  1121. realOutput.writeShort(cast_array[i]);
  1122. return;
  1123. }
  1124. }
  1125. else
  1126. {
  1127. Object[] cast_array = (Object[])array;
  1128. realOutput.writeInt(length);
  1129. for (int i = 0; i < length; i++)
  1130. writeObject(cast_array[i]);
  1131. }
  1132. }
  1133. /* GCJ LOCAL */
  1134. // writes out FIELDS of OBJECT for the specified ObjectStreamClass.
  1135. // FIELDS are already supposed already to be in canonical order, but
  1136. // under some circumstances (to do with Proxies) this isn't the
  1137. // case, so we call ensureFieldsSet().
  1138. private void writeFields(Object obj, ObjectStreamClass osc)
  1139. throws IOException
  1140. {
  1141. osc.ensureFieldsSet(osc.forClass());
  1142. /* END GCJ LOCAL */
  1143. ObjectStreamField[] fields = osc.fields;
  1144. boolean oldmode = setBlockDataMode(false);
  1145. try
  1146. {
  1147. writeFields(obj,fields);
  1148. }
  1149. catch (IllegalArgumentException _)
  1150. {
  1151. InvalidClassException e = new InvalidClassException
  1152. ("writing fields of class " + osc.forClass().getName());
  1153. e.initCause(_);
  1154. throw e;
  1155. }
  1156. catch (IOException e)
  1157. {
  1158. throw e;
  1159. }
  1160. catch (Exception _)
  1161. {
  1162. IOException e = new IOException("Unexpected exception " + _);
  1163. e.initCause(_);
  1164. throw(e);
  1165. }
  1166. setBlockDataMode(oldmode);
  1167. }
  1168. /**
  1169. * Helper function for writeFields(Object,ObjectStreamClass): write
  1170. * fields from given fields array. Pass exception on.
  1171. *
  1172. * @param obj the object to be written
  1173. *
  1174. * @param fields the fields of obj to be written.
  1175. */
  1176. private void writeFields(Object obj, ObjectStreamField[] fields)
  1177. throws
  1178. IllegalArgumentException, IllegalAccessException, IOException
  1179. {
  1180. for (int i = 0; i < fields.length; i++)
  1181. {
  1182. ObjectStreamField osf = fields[i];
  1183. Field field = osf.field;
  1184. if (DEBUG && dump)
  1185. dumpElementln ("WRITE FIELD: " + osf.getName() + " type=" + osf.getType());
  1186. switch (osf.getTypeCode())
  1187. {
  1188. case 'Z': realOutput.writeBoolean(field.getBoolean(obj)); break;
  1189. case 'B': realOutput.writeByte (field.getByte (obj)); break;
  1190. case 'S': realOutput.writeShort (field.getShort (obj)); break;
  1191. case 'C': realOutput.writeChar (field.getChar (obj)); break;
  1192. case 'I': realOutput.writeInt (field.getInt (obj)); break;
  1193. case 'F': realOutput.writeFloat (field.getFloat (obj)); break;
  1194. case 'J': realOutput.writeLong (field.getLong (obj)); break;
  1195. case 'D': realOutput.writeDouble (field.getDouble (obj)); break;
  1196. case 'L':
  1197. case '[': writeObject (field.get (obj)); break;
  1198. default:
  1199. throw new IOException("Unexpected type code " + osf.getTypeCode());
  1200. }
  1201. }
  1202. }
  1203. // Toggles writing primitive data to block-data buffer.
  1204. // Package-private to avoid a trampoline constructor.
  1205. boolean setBlockDataMode(boolean on) throws IOException
  1206. {
  1207. if (on == writeDataAsBlocks)
  1208. return on;
  1209. drain();
  1210. boolean oldmode = writeDataAsBlocks;
  1211. writeDataAsBlocks = on;
  1212. if (on)
  1213. dataOutput = blockDataOutput;
  1214. else
  1215. dataOutput = realOutput;
  1216. return oldmode;
  1217. }
  1218. private void callWriteMethod(Object obj, ObjectStreamClass osc)
  1219. throws IOException
  1220. {
  1221. currentPutField = null;
  1222. try
  1223. {
  1224. Object args[] = {this};
  1225. osc.writeObjectMethod.invoke(obj, args);
  1226. }
  1227. catch (InvocationTargetException x)
  1228. {
  1229. /* Rethrow if possible. */
  1230. Throwable exception = x.getTargetException();
  1231. if (exception instanceof RuntimeException)
  1232. throw (RuntimeException) exception;
  1233. if (exception instanceof IOException)
  1234. throw (IOException) exception;
  1235. IOException ioe
  1236. = new IOException("Exception thrown from writeObject() on " +
  1237. osc.forClass().getName() + ": " +
  1238. exception.getClass().getName());
  1239. ioe.initCause(exception);
  1240. throw ioe;
  1241. }
  1242. catch (Exception x)
  1243. {
  1244. IOException ioe
  1245. = new IOException("Failure invoking writeObject() on " +
  1246. osc.forClass().getName() + ": " +
  1247. x.getClass().getName());
  1248. ioe.initCause(x);
  1249. throw ioe;
  1250. }
  1251. }
  1252. private void dumpElementln (String msg, Object obj)
  1253. {
  1254. try
  1255. {
  1256. for (int i = 0; i < depth; i++)
  1257. System.out.print (" ");
  1258. System.out.print (Thread.currentThread() + ": ");
  1259. System.out.print (msg);
  1260. if (java.lang.reflect.Proxy.isProxyClass(obj.getClass()))
  1261. System.out.print (obj.getClass());
  1262. else
  1263. System.out.print (obj);
  1264. }
  1265. catch (Exception _)
  1266. {
  1267. }
  1268. finally
  1269. {
  1270. System.out.println ();
  1271. }
  1272. }
  1273. private void dumpElementln (String msg)
  1274. {
  1275. for (int i = 0; i < depth; i++)
  1276. System.out.print (" ");
  1277. System.out.print (Thread.currentThread() + ": ");
  1278. System.out.println(msg);
  1279. }
  1280. // this value comes from 1.2 spec, but is used in 1.1 as well
  1281. private static final int BUFFER_SIZE = 1024;
  1282. private static int defaultProtocolVersion = PROTOCOL_VERSION_2;
  1283. private DataOutputStream dataOutput;
  1284. private boolean writeDataAsBlocks;
  1285. private DataOutputStream realOutput;
  1286. private DataOutputStream blockDataOutput;
  1287. private byte[] blockData;
  1288. private int blockDataCount;
  1289. private Object currentObject;
  1290. // Package-private to avoid a trampoline.
  1291. ObjectStreamClass currentObjectStreamClass;
  1292. private PutField currentPutField;
  1293. private boolean fieldsAlreadyWritten;
  1294. private boolean replacementEnabled;
  1295. private boolean isSerializing;
  1296. private int nextOID;
  1297. private ObjectIdentityMap2Int OIDLookupTable;
  1298. private int protocolVersion;
  1299. private boolean useSubclassMethod;
  1300. private SetAccessibleAction setAccessible = new SetAccessibleAction();
  1301. // The nesting depth for debugging output
  1302. private int depth = 0;
  1303. // Set if we're generating debugging dumps
  1304. private boolean dump = false;
  1305. private static final boolean DEBUG = false;
  1306. /**
  1307. * Returns true if the given class overrides either of the
  1308. * methods <code>putFields</code> or <code>writeUnshared</code>.
  1309. *
  1310. * @param clazz the class to check.
  1311. * @return true if the class overrides one of the methods.
  1312. */
  1313. private static boolean overridesMethods(final Class<?> clazz)
  1314. {
  1315. if (clazz == ObjectOutputStream.class)
  1316. return false;
  1317. return AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
  1318. public Boolean run()
  1319. {
  1320. Method[] methods = clazz.getDeclaredMethods();
  1321. for (int a = 0; a < methods.length; ++a)
  1322. {
  1323. String name = methods[a].getName();
  1324. if (name.equals("writeUnshared"))
  1325. {
  1326. Class<?>[] paramTypes = methods[a].getParameterTypes();
  1327. if (paramTypes.length == 1 &&
  1328. paramTypes[0] == Object.class &&
  1329. methods[a].getReturnType() == Void.class)
  1330. return true;
  1331. }
  1332. else if (name.equals("putFields"))
  1333. {
  1334. if (methods[a].getParameterTypes().length == 0 &&
  1335. methods[a].getReturnType() == PutField.class)
  1336. return true;
  1337. }
  1338. }
  1339. return false;
  1340. }
  1341. });
  1342. }
  1343. }