12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144 |
- /* ObjectInputStream.java -- Class used to read serialized objects
- Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2005, 2006, 2008
- Free Software Foundation, Inc.
- This file is part of GNU Classpath.
- GNU Classpath is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
- GNU Classpath is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with GNU Classpath; see the file COPYING. If not, write to the
- Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- 02110-1301 USA.
- Linking this library statically or dynamically with other modules is
- making a combined work based on this library. Thus, the terms and
- conditions of the GNU General Public License cover the whole
- combination.
- As a special exception, the copyright holders of this library give you
- permission to link this library with independent modules to produce an
- executable, regardless of the license terms of these independent
- modules, and to copy and distribute the resulting executable under
- terms of your choice, provided that you also meet, for each linked
- independent module, the terms and conditions of the license of that
- module. An independent module is a module which is not derived from
- or based on this library. If you modify this library, you may extend
- this exception to your version of the library, but you are not
- obligated to do so. If you do not wish to do so, delete this
- exception statement from your version. */
- package java.io;
- import gnu.classpath.Pair;
- import gnu.classpath.VMStackWalker;
- import java.lang.reflect.Array;
- import java.lang.reflect.Constructor;
- import java.lang.reflect.Field;
- import java.lang.reflect.InvocationTargetException;
- import java.lang.reflect.Method;
- import java.lang.reflect.Modifier;
- import java.lang.reflect.Proxy;
- import java.security.AccessController;
- import java.security.PrivilegedAction;
- import java.util.HashMap;
- import java.util.Hashtable;
- import java.util.Iterator;
- import java.util.Map;
- import java.util.TreeSet;
- /**
- * @author Tom Tromey (tromey@redhat.com)
- * @author Jeroen Frijters (jeroen@frijters.net)
- * @author Guilhem Lavaux (guilhem@kaffe.org)
- * @author Michael Koch (konqueror@gmx.de)
- * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
- */
- public class ObjectInputStream extends InputStream
- implements ObjectInput, ObjectStreamConstants
- {
- /**
- * Creates a new <code>ObjectInputStream</code> that will do all of
- * its reading from <code>in</code>. This method also checks
- * the stream by reading the header information (stream magic number
- * and stream version).
- *
- * @exception IOException Reading stream header from underlying
- * stream cannot be completed.
- *
- * @exception StreamCorruptedException An invalid stream magic
- * number or stream version was read from the stream.
- *
- * @see #readStreamHeader()
- */
- public ObjectInputStream(InputStream in)
- throws IOException, StreamCorruptedException
- {
- if (DEBUG)
- {
- String val = System.getProperty("gcj.dumpobjects");
- if (dump == false && val != null && !val.equals(""))
- {
- dump = true;
- System.out.println ("Serialization debugging enabled");
- }
- else if (dump == true && (val == null || val.equals("")))
- {
- dump = false;
- System.out.println ("Serialization debugging disabled");
- }
- }
- this.resolveEnabled = false;
- this.blockDataPosition = 0;
- this.blockDataBytes = 0;
- this.blockData = new byte[BUFFER_SIZE];
- this.blockDataInput = new DataInputStream(this);
- this.realInputStream = new DataInputStream(in);
- this.nextOID = baseWireHandle;
- handles = new HashMap<Integer,Pair<Boolean,Object>>();
- this.classLookupTable = new Hashtable<Class,ObjectStreamClass>();
- setBlockDataMode(true);
- readStreamHeader();
- }
- /**
- * Returns the next deserialized object read from the underlying stream.
- *
- * This method can be overriden by a class by implementing
- * <code>private void readObject (ObjectInputStream)</code>.
- *
- * If an exception is thrown from this method, the stream is left in
- * an undefined state. This method can also throw Errors and
- * RuntimeExceptions if caused by existing readResolve() user code.
- *
- * @return The object read from the underlying stream.
- *
- * @exception ClassNotFoundException The class that an object being
- * read in belongs to cannot be found.
- *
- * @exception IOException Exception from underlying
- * <code>InputStream</code>.
- */
- public final Object readObject()
- throws ClassNotFoundException, IOException
- {
- return readObject(true);
- }
- /**
- * <p>
- * Returns the next deserialized object read from the
- * underlying stream in an unshared manner. Any object
- * returned by this method will not be returned by
- * subsequent calls to either this method or {@link #readObject()}.
- * </p>
- * <p>
- * This behaviour is achieved by:
- * </p>
- * <ul>
- * <li>Marking the handles created by successful calls to this
- * method, so that future calls to {@link #readObject()} or
- * {@link #readUnshared()} will throw an {@link ObjectStreamException}
- * rather than returning the same object reference.</li>
- * <li>Throwing an {@link ObjectStreamException} if the next
- * element in the stream is a reference to an earlier object.</li>
- * </ul>
- *
- * @return a reference to the deserialized object.
- * @throws ClassNotFoundException if the class of the object being
- * deserialized can not be found.
- * @throws StreamCorruptedException if information in the stream
- * is inconsistent.
- * @throws ObjectStreamException if the next object has already been
- * returned by an earlier call to this
- * method or {@link #readObject()}.
- * @throws OptionalDataException if primitive data occurs next in the stream.
- * @throws IOException if an I/O error occurs from the stream.
- * @since 1.4
- * @see #readObject()
- */
- public Object readUnshared()
- throws IOException, ClassNotFoundException
- {
- return readObject(false);
- }
- /**
- * Returns the next deserialized object read from the underlying stream.
- *
- * This method can be overriden by a class by implementing
- * <code>private void readObject (ObjectInputStream)</code>.
- *
- * If an exception is thrown from this method, the stream is left in
- * an undefined state. This method can also throw Errors and
- * RuntimeExceptions if caused by existing readResolve() user code.
- *
- * @param shared true if handles created by this call should be shared
- * with later calls.
- * @return The object read from the underlying stream.
- *
- * @exception ClassNotFoundException The class that an object being
- * read in belongs to cannot be found.
- *
- * @exception IOException Exception from underlying
- * <code>InputStream</code>.
- */
- private final Object readObject(boolean shared)
- throws ClassNotFoundException, IOException
- {
- if (this.useSubclassMethod)
- return readObjectOverride();
- Object ret_val;
- boolean old_mode = setBlockDataMode(false);
- byte marker = this.realInputStream.readByte();
- if (DEBUG)
- depth += 2;
- if(dump) dumpElement("MARKER: 0x" + Integer.toHexString(marker) + " ");
- try
- {
- ret_val = parseContent(marker, shared);
- }
- finally
- {
- setBlockDataMode(old_mode);
- if (DEBUG)
- depth -= 2;
- }
- return ret_val;
- }
- /**
- * Handles a content block within the stream, which begins with a marker
- * byte indicating its type.
- *
- * @param marker the byte marker.
- * @param shared true if handles created by this call should be shared
- * with later calls.
- * @return an object which represents the parsed content.
- * @throws ClassNotFoundException if the class of an object being
- * read in cannot be found.
- * @throws IOException if invalid data occurs or one is thrown by the
- * underlying <code>InputStream</code>.
- */
- private Object parseContent(byte marker, boolean shared)
- throws ClassNotFoundException, IOException
- {
- Object ret_val;
- boolean is_consumed = false;
- switch (marker)
- {
- case TC_ENDBLOCKDATA:
- {
- ret_val = null;
- is_consumed = true;
- break;
- }
- case TC_BLOCKDATA:
- case TC_BLOCKDATALONG:
- {
- if (marker == TC_BLOCKDATALONG)
- { if(dump) dumpElementln("BLOCKDATALONG"); }
- else
- { if(dump) dumpElementln("BLOCKDATA"); }
- readNextBlock(marker);
- }
- case TC_NULL:
- {
- if(dump) dumpElementln("NULL");
- ret_val = null;
- break;
- }
- case TC_REFERENCE:
- {
- if(dump) dumpElement("REFERENCE ");
- int oid = realInputStream.readInt();
- if(dump) dumpElementln(Integer.toHexString(oid));
- ret_val = lookupHandle(oid);
- if (!shared)
- throw new
- InvalidObjectException("References can not be read unshared.");
- break;
- }
- case TC_CLASS:
- {
- if(dump) dumpElementln("CLASS");
- ObjectStreamClass osc = (ObjectStreamClass)readObject();
- Class clazz = osc.forClass();
- assignNewHandle(clazz,shared);
- ret_val = clazz;
- break;
- }
- case TC_PROXYCLASSDESC:
- {
- if(dump) dumpElementln("PROXYCLASS");
- /* GCJ LOCAL */
- // The grammar at this point is
- // TC_PROXYCLASSDESC newHandle proxyClassDescInfo
- // i.e. we have to assign the handle immediately after
- // reading the marker.
- int handle = assignNewHandle("Dummy proxy",shared);
- /* END GCJ LOCAL */
- int n_intf = this.realInputStream.readInt();
- String[] intfs = new String[n_intf];
- for (int i = 0; i < n_intf; i++)
- {
- intfs[i] = this.realInputStream.readUTF();
- }
- boolean oldmode = setBlockDataMode(true);
- Class cl = resolveProxyClass(intfs);
- setBlockDataMode(oldmode);
- ObjectStreamClass osc = lookupClass(cl);
- if (osc.firstNonSerializableParentConstructor == null)
- {
- osc.realClassIsSerializable = true;
- osc.fields = osc.fieldMapping = new ObjectStreamField[0];
- try
- {
- osc.firstNonSerializableParentConstructor =
- Object.class.getConstructor(new Class[0]);
- }
- catch (NoSuchMethodException x)
- {
- throw (InternalError)
- new InternalError("Object ctor missing").initCause(x);
- }
- }
- /* GCJ LOCAL */
- rememberHandle(osc,shared,handle);
- /* END GCJ LOCAL */
- if (!is_consumed)
- {
- byte b = this.realInputStream.readByte();
- if (b != TC_ENDBLOCKDATA)
- throw new IOException("Data annotated to class was not consumed." + b);
- }
- else
- is_consumed = false;
- ObjectStreamClass superosc = (ObjectStreamClass)readObject();
- osc.setSuperclass(superosc);
- ret_val = osc;
- break;
- }
- case TC_CLASSDESC:
- {
- ObjectStreamClass osc = readClassDescriptor();
- if (!is_consumed)
- {
- byte b = this.realInputStream.readByte();
- if (b != TC_ENDBLOCKDATA)
- throw new IOException("Data annotated to class was not consumed." + b);
- }
- else
- is_consumed = false;
- osc.setSuperclass ((ObjectStreamClass)readObject());
- ret_val = osc;
- break;
- }
- case TC_STRING:
- {
- if(dump) dumpElement("STRING=");
- String s = this.realInputStream.readUTF();
- if(dump) dumpElementln(s);
- ret_val = processResolution(null, s, assignNewHandle(s,shared),
- shared);
- break;
- }
- case TC_LONGSTRING:
- {
- if(dump) dumpElement("STRING=");
- String s = this.realInputStream.readUTFLong();
- if(dump) dumpElementln(s);
- ret_val = processResolution(null, s, assignNewHandle(s,shared),
- shared);
- break;
- }
- case TC_ARRAY:
- {
- if(dump) dumpElementln("ARRAY");
- ObjectStreamClass osc = (ObjectStreamClass)readObject();
- Class componentType = osc.forClass().getComponentType();
- if(dump) dumpElement("ARRAY LENGTH=");
- int length = this.realInputStream.readInt();
- if(dump) dumpElementln (length + "; COMPONENT TYPE=" + componentType);
- Object array = Array.newInstance(componentType, length);
- int handle = assignNewHandle(array,shared);
- readArrayElements(array, componentType);
- if(dump)
- for (int i = 0, len = Array.getLength(array); i < len; i++)
- dumpElementln(" ELEMENT[" + i + "]=", Array.get(array, i));
- ret_val = processResolution(null, array, handle, shared);
- break;
- }
- case TC_OBJECT:
- {
- if(dump) dumpElementln("OBJECT");
- ObjectStreamClass osc = (ObjectStreamClass)readObject();
- Class clazz = osc.forClass();
- if (!osc.realClassIsSerializable)
- throw new NotSerializableException
- (clazz + " is not Serializable, and thus cannot be deserialized.");
- if (osc.realClassIsExternalizable)
- {
- Externalizable obj = osc.newInstance();
- int handle = assignNewHandle(obj,shared);
- boolean read_from_blocks = ((osc.getFlags() & SC_BLOCK_DATA) != 0);
- boolean oldmode = this.readDataFromBlock;
- if (read_from_blocks)
- setBlockDataMode(true);
- obj.readExternal(this);
- if (read_from_blocks)
- {
- setBlockDataMode(oldmode);
- if (!oldmode)
- if (this.realInputStream.readByte() != TC_ENDBLOCKDATA)
- throw new IOException("No end of block data seen for class with readExternal (ObjectInputStream) method.");
- }
- ret_val = processResolution(osc, obj, handle,shared);
- break;
- } // end if (osc.realClassIsExternalizable)
- Object obj = newObject(clazz, osc.firstNonSerializableParentConstructor);
- int handle = assignNewHandle(obj,shared);
- Object prevObject = this.currentObject;
- ObjectStreamClass prevObjectStreamClass = this.currentObjectStreamClass;
- TreeSet<ValidatorAndPriority> prevObjectValidators =
- this.currentObjectValidators;
- this.currentObject = obj;
- this.currentObjectValidators = null;
- ObjectStreamClass[] hierarchy = hierarchy(clazz);
- for (int i = 0; i < hierarchy.length; i++)
- {
- this.currentObjectStreamClass = hierarchy[i];
- if(dump) dumpElementln("Reading fields of " + this.currentObjectStreamClass.getName ());
- // XXX: should initialize fields in classes in the hierarchy
- // that aren't in the stream
- // should skip over classes in the stream that aren't in the
- // real classes hierarchy
- Method readObjectMethod = this.currentObjectStreamClass.readObjectMethod;
- if (readObjectMethod != null)
- {
- fieldsAlreadyRead = false;
- boolean oldmode = setBlockDataMode(true);
- callReadMethod(readObjectMethod, this.currentObjectStreamClass.forClass(), obj);
- setBlockDataMode(oldmode);
- }
- else
- {
- readFields(obj, currentObjectStreamClass);
- }
- if (this.currentObjectStreamClass.hasWriteMethod())
- {
- if(dump) dumpElement("ENDBLOCKDATA? ");
- try
- {
- /* Read blocks until an end marker */
- byte writeMarker = this.realInputStream.readByte();
- while (writeMarker != TC_ENDBLOCKDATA)
- {
- parseContent(writeMarker, shared);
- writeMarker = this.realInputStream.readByte();
- }
- if(dump) dumpElementln("yes");
- }
- catch (EOFException e)
- {
- throw (IOException) new IOException
- ("No end of block data seen for class with readObject (ObjectInputStream) method.").initCause(e);
- }
- }
- }
- this.currentObject = prevObject;
- this.currentObjectStreamClass = prevObjectStreamClass;
- ret_val = processResolution(osc, obj, handle, shared);
- if (currentObjectValidators != null)
- invokeValidators();
- this.currentObjectValidators = prevObjectValidators;
- break;
- }
- case TC_RESET:
- if(dump) dumpElementln("RESET");
- clearHandles();
- ret_val = readObject();
- break;
- case TC_EXCEPTION:
- {
- if(dump) dumpElement("EXCEPTION=");
- Exception e = (Exception)readObject();
- if(dump) dumpElementln(e.toString());
- clearHandles();
- throw new WriteAbortedException("Exception thrown during writing of stream", e);
- }
- case TC_ENUM:
- {
- /* TC_ENUM classDesc newHandle enumConstantName */
- if (dump)
- dumpElementln("ENUM=");
- ObjectStreamClass osc = (ObjectStreamClass) readObject();
- int enumHandle = assignNewHandle(null, shared);
- String constantName = (String) readObject();
- if (dump)
- dumpElementln("CONSTANT NAME = " + constantName);
- Class clazz = osc.forClass();
- Enum instance = Enum.valueOf(clazz, constantName);
- rememberHandle(instance, shared, enumHandle);
- ret_val = instance;
- break;
- }
- default:
- throw new IOException("Unknown marker on stream: " + marker);
- }
- return ret_val;
- }
- /**
- * This method makes a partial check of types for the fields
- * contained given in arguments. It checks primitive types of
- * fields1 against non primitive types of fields2. This method
- * assumes the two lists has already been sorted according to
- * the Java specification.
- *
- * @param name Name of the class owning the given fields.
- * @param fields1 First list to check.
- * @param fields2 Second list to check.
- * @throws InvalidClassException if a field in fields1, which has a primitive type, is a present
- * in the non primitive part in fields2.
- */
- private void checkTypeConsistency(String name, ObjectStreamField[] fields1, ObjectStreamField[] fields2)
- throws InvalidClassException
- {
- int nonPrimitive = 0;
- for (nonPrimitive = 0;
- nonPrimitive < fields1.length
- && fields1[nonPrimitive].isPrimitive(); nonPrimitive++)
- {
- }
- if (nonPrimitive == fields1.length)
- return;
- int i = 0;
- ObjectStreamField f1;
- ObjectStreamField f2;
- while (i < fields2.length
- && nonPrimitive < fields1.length)
- {
- f1 = fields1[nonPrimitive];
- f2 = fields2[i];
- if (!f2.isPrimitive())
- break;
- int compVal = f1.getName().compareTo (f2.getName());
- if (compVal < 0)
- {
- nonPrimitive++;
- }
- else if (compVal > 0)
- {
- i++;
- }
- else
- {
- throw new InvalidClassException
- ("invalid field type for " + f2.getName() +
- " in class " + name);
- }
- }
- }
- /**
- * This method reads a class descriptor from the real input stream
- * and use these data to create a new instance of ObjectStreamClass.
- * Fields are sorted and ordered for the real read which occurs for
- * each instance of the described class. Be aware that if you call that
- * method you must ensure that the stream is synchronized, in the other
- * case it may be completely desynchronized.
- *
- * @return A new instance of ObjectStreamClass containing the freshly
- * created descriptor.
- * @throws ClassNotFoundException if the required class to build the
- * descriptor has not been found in the system.
- * @throws IOException An input/output error occured.
- * @throws InvalidClassException If there was a compatibility problem
- * between the class present in the system and the serialized class.
- */
- protected ObjectStreamClass readClassDescriptor()
- throws ClassNotFoundException, IOException
- {
- if(dump) dumpElement("CLASSDESC NAME=");
- String name = this.realInputStream.readUTF();
- if(dump) dumpElement(name + "; UID=");
- long uid = this.realInputStream.readLong ();
- if(dump) dumpElement(Long.toHexString(uid) + "; FLAGS=");
- byte flags = this.realInputStream.readByte ();
- if(dump) dumpElement(Integer.toHexString(flags) + "; FIELD COUNT=");
- short field_count = this.realInputStream.readShort();
- if(dump) dumpElementln(Short.toString(field_count));
- ObjectStreamField[] fields = new ObjectStreamField[field_count];
- ObjectStreamClass osc = new ObjectStreamClass(name, uid,
- flags, fields);
- assignNewHandle(osc,true);
- for (int i = 0; i < field_count; i++)
- {
- if(dump) dumpElement(" TYPE CODE=");
- char type_code = (char)this.realInputStream.readByte();
- if(dump) dumpElement(type_code + "; FIELD NAME=");
- String field_name = this.realInputStream.readUTF();
- if(dump) dumpElementln(field_name);
- String class_name;
- // If the type code is an array or an object we must
- // decode a String here. In the other case we convert
- // the type code and pass it to ObjectStreamField.
- // Type codes are decoded by gnu.java.lang.reflect.TypeSignature.
- if (type_code == 'L' || type_code == '[')
- class_name = (String)readObject();
- else
- class_name = String.valueOf(type_code);
- fields[i] =
- new ObjectStreamField(field_name, class_name);
- }
- /* Now that fields have been read we may resolve the class
- * (and read annotation if needed). */
- Class clazz = resolveClass(osc);
- ClassLoader loader = clazz.getClassLoader();
- for (int i = 0; i < field_count; i++)
- {
- fields[i].resolveType(loader);
- }
- boolean oldmode = setBlockDataMode(true);
- osc.setClass(clazz, lookupClass(clazz.getSuperclass()));
- classLookupTable.put(clazz, osc);
- setBlockDataMode(oldmode);
- // find the first non-serializable class in clazz's inheritance hierarchy
- Class first_nonserial = clazz.getSuperclass();
- // Maybe it is a primitive class, those don't have a super class,
- // or Object itself. Otherwise we can keep getting the superclass
- // till we hit the Object class, or some other non-serializable class.
- if (first_nonserial == null)
- first_nonserial = clazz;
- else
- while (Serializable.class.isAssignableFrom(first_nonserial))
- first_nonserial = first_nonserial.getSuperclass();
- final Class local_constructor_class = first_nonserial;
- osc.firstNonSerializableParentConstructor =
- (Constructor)AccessController.doPrivileged(new PrivilegedAction()
- {
- public Object run()
- {
- try
- {
- Constructor c = local_constructor_class.
- getDeclaredConstructor(new Class[0]);
- if (Modifier.isPrivate(c.getModifiers()))
- return null;
- return c;
- }
- catch (NoSuchMethodException e)
- {
- // error will be reported later, in newObject()
- return null;
- }
- }
- });
- osc.realClassIsSerializable = Serializable.class.isAssignableFrom(clazz);
- osc.realClassIsExternalizable = Externalizable.class.isAssignableFrom(clazz);
- ObjectStreamField[] stream_fields = osc.fields;
- ObjectStreamField[] real_fields = ObjectStreamClass.lookupForClassObject(clazz).fields;
- ObjectStreamField[] fieldmapping = new ObjectStreamField[2 * Math.max(stream_fields.length, real_fields.length)];
- int stream_idx = 0;
- int real_idx = 0;
- int map_idx = 0;
- /*
- * Check that there is no type inconsistencies between the lists.
- * A special checking must be done for the two groups: primitive types and
- * not primitive types.
- */
- checkTypeConsistency(name, real_fields, stream_fields);
- checkTypeConsistency(name, stream_fields, real_fields);
- while (stream_idx < stream_fields.length
- || real_idx < real_fields.length)
- {
- ObjectStreamField stream_field = null;
- ObjectStreamField real_field = null;
- if (stream_idx == stream_fields.length)
- {
- real_field = real_fields[real_idx++];
- }
- else if (real_idx == real_fields.length)
- {
- stream_field = stream_fields[stream_idx++];
- }
- else
- {
- int comp_val =
- real_fields[real_idx].compareTo (stream_fields[stream_idx]);
- if (comp_val < 0)
- {
- real_field = real_fields[real_idx++];
- }
- else if (comp_val > 0)
- {
- stream_field = stream_fields[stream_idx++];
- }
- else
- {
- stream_field = stream_fields[stream_idx++];
- real_field = real_fields[real_idx++];
- if (stream_field.getType() != real_field.getType())
- throw new InvalidClassException
- ("invalid field type for " + real_field.getName() +
- " in class " + name);
- }
- }
- /* If some of stream_fields does not correspond to any of real_fields,
- * or the opposite, then fieldmapping will go short.
- */
- if (map_idx == fieldmapping.length)
- {
- ObjectStreamField[] newfieldmapping =
- new ObjectStreamField[fieldmapping.length + 2];
- System.arraycopy(fieldmapping, 0,
- newfieldmapping, 0, fieldmapping.length);
- fieldmapping = newfieldmapping;
- }
- fieldmapping[map_idx++] = stream_field;
- fieldmapping[map_idx++] = real_field;
- }
- osc.fieldMapping = fieldmapping;
- return osc;
- }
- /**
- * Reads the current objects non-transient, non-static fields from
- * the current class from the underlying output stream.
- *
- * This method is intended to be called from within a object's
- * <code>private void readObject (ObjectInputStream)</code>
- * method.
- *
- * @exception ClassNotFoundException The class that an object being
- * read in belongs to cannot be found.
- *
- * @exception NotActiveException This method was called from a
- * context other than from the current object's and current class's
- * <code>private void readObject (ObjectInputStream)</code>
- * method.
- *
- * @exception IOException Exception from underlying
- * <code>OutputStream</code>.
- */
- public void defaultReadObject()
- throws ClassNotFoundException, IOException, NotActiveException
- {
- if (this.currentObject == null || this.currentObjectStreamClass == null)
- throw new NotActiveException("defaultReadObject called by non-active"
- + " class and/or object");
- if (fieldsAlreadyRead)
- throw new NotActiveException("defaultReadObject called but fields "
- + "already read from stream (by "
- + "defaultReadObject or readFields)");
- boolean oldmode = setBlockDataMode(false);
- readFields(this.currentObject, this.currentObjectStreamClass);
- setBlockDataMode(oldmode);
- fieldsAlreadyRead = true;
- }
- /**
- * Registers a <code>ObjectInputValidation</code> to be carried out
- * on the object graph currently being deserialized before it is
- * returned to the original caller of <code>readObject ()</code>.
- * The order of validation for multiple
- * <code>ObjectInputValidation</code>s can be controled using
- * <code>priority</code>. Validators with higher priorities are
- * called first.
- *
- * @see java.io.ObjectInputValidation
- *
- * @exception InvalidObjectException <code>validator</code> is
- * <code>null</code>
- *
- * @exception NotActiveException an attempt was made to add a
- * validator outside of the <code>readObject</code> method of the
- * object currently being deserialized
- */
- public void registerValidation(ObjectInputValidation validator,
- int priority)
- throws InvalidObjectException, NotActiveException
- {
- if (this.currentObject == null || this.currentObjectStreamClass == null)
- throw new NotActiveException("registerValidation called by non-active "
- + "class and/or object");
- if (validator == null)
- throw new InvalidObjectException("attempt to add a null "
- + "ObjectInputValidation object");
- if (currentObjectValidators == null)
- currentObjectValidators = new TreeSet<ValidatorAndPriority>();
- currentObjectValidators.add(new ValidatorAndPriority(validator, priority));
- }
- /**
- * Called when a class is being deserialized. This is a hook to
- * allow subclasses to read in information written by the
- * <code>annotateClass (Class)</code> method of an
- * <code>ObjectOutputStream</code>.
- *
- * This implementation looks up the active call stack for a
- * <code>ClassLoader</code>; if a <code>ClassLoader</code> is found,
- * it is used to load the class associated with <code>osc</code>,
- * otherwise, the default system <code>ClassLoader</code> is used.
- *
- * @exception IOException Exception from underlying
- * <code>OutputStream</code>.
- *
- * @see java.io.ObjectOutputStream#annotateClass (java.lang.Class)
- */
- protected Class<?> resolveClass(ObjectStreamClass osc)
- throws ClassNotFoundException, IOException
- {
- String name = osc.getName();
- try
- {
- return Class.forName(name, true, currentLoader());
- }
- catch(ClassNotFoundException x)
- {
- if (name.equals("void"))
- return Void.TYPE;
- else if (name.equals("boolean"))
- return Boolean.TYPE;
- else if (name.equals("byte"))
- return Byte.TYPE;
- else if (name.equals("char"))
- return Character.TYPE;
- else if (name.equals("short"))
- return Short.TYPE;
- else if (name.equals("int"))
- return Integer.TYPE;
- else if (name.equals("long"))
- return Long.TYPE;
- else if (name.equals("float"))
- return Float.TYPE;
- else if (name.equals("double"))
- return Double.TYPE;
- else
- throw x;
- }
- }
- /**
- * Returns the most recent user defined ClassLoader on the execution stack
- * or null if none is found.
- */
- private ClassLoader currentLoader()
- {
- return VMStackWalker.firstNonNullClassLoader();
- }
- /**
- * Lookup a class stored in the local hashtable. If it is not
- * use the global lookup function in ObjectStreamClass to build
- * the ObjectStreamClass. This method is requested according to
- * the behaviour detected in the JDK by Kaffe's team.
- *
- * @param clazz Class to lookup in the hash table or for which
- * we must build a descriptor.
- * @return A valid instance of ObjectStreamClass corresponding
- * to the specified class.
- */
- private ObjectStreamClass lookupClass(Class clazz)
- {
- if (clazz == null)
- return null;
- ObjectStreamClass oclazz;
- oclazz = classLookupTable.get(clazz);
- if (oclazz == null)
- return ObjectStreamClass.lookup(clazz);
- else
- return oclazz;
- }
- /**
- * Reconstruct class hierarchy the same way {@link
- * java.io.ObjectStreamClass#hierarchy} does but using lookupClass
- * instead of ObjectStreamClass.lookup.
- *
- * @param clazz This is the class for which we want the hierarchy.
- *
- * @return An array of valid {@link java.io.ObjectStreamClass} instances which
- * represent the class hierarchy for clazz.
- */
- private ObjectStreamClass[] hierarchy(Class clazz)
- {
- ObjectStreamClass osc = lookupClass(clazz);
- return osc == null ? new ObjectStreamClass[0] : osc.hierarchy();
- }
- /**
- * Allows subclasses to resolve objects that are read from the
- * stream with other objects to be returned in their place. This
- * method is called the first time each object is encountered.
- *
- * This method must be enabled before it will be called in the
- * serialization process.
- *
- * @exception IOException Exception from underlying
- * <code>OutputStream</code>.
- *
- * @see #enableResolveObject(boolean)
- */
- protected Object resolveObject(Object obj) throws IOException
- {
- return obj;
- }
- protected Class<?> resolveProxyClass(String[] intfs)
- throws IOException, ClassNotFoundException
- {
- ClassLoader cl = currentLoader();
- Class<?>[] clss = new Class<?>[intfs.length];
- if(cl == null)
- {
- for (int i = 0; i < intfs.length; i++)
- clss[i] = Class.forName(intfs[i]);
- cl = ClassLoader.getSystemClassLoader();
- }
- else
- for (int i = 0; i < intfs.length; i++)
- clss[i] = Class.forName(intfs[i], false, cl);
- try
- {
- return Proxy.getProxyClass(cl, clss);
- }
- catch (IllegalArgumentException e)
- {
- throw new ClassNotFoundException(null, e);
- }
- }
- /**
- * If <code>enable</code> is <code>true</code> and this object is
- * trusted, then <code>resolveObject (Object)</code> will be called
- * in subsequent calls to <code>readObject (Object)</code>.
- * Otherwise, <code>resolveObject (Object)</code> will not be called.
- *
- * @exception SecurityException This class is not trusted.
- */
- protected boolean enableResolveObject (boolean enable)
- throws SecurityException
- {
- if (enable)
- {
- SecurityManager sm = System.getSecurityManager();
- if (sm != null)
- sm.checkPermission(new SerializablePermission("enableSubstitution"));
- }
- boolean old_val = this.resolveEnabled;
- this.resolveEnabled = enable;
- return old_val;
- }
- /**
- * Reads stream magic and stream version information from the
- * underlying stream.
- *
- * @exception IOException Exception from underlying stream.
- *
- * @exception StreamCorruptedException An invalid stream magic
- * number or stream version was read from the stream.
- */
- protected void readStreamHeader()
- throws IOException, StreamCorruptedException
- {
- if(dump) dumpElement("STREAM MAGIC ");
- if (this.realInputStream.readShort() != STREAM_MAGIC)
- throw new StreamCorruptedException("Invalid stream magic number");
- if(dump) dumpElementln("STREAM VERSION ");
- if (this.realInputStream.readShort() != STREAM_VERSION)
- throw new StreamCorruptedException("Invalid stream version number");
- }
- public int read() throws IOException
- {
- if (this.readDataFromBlock)
- {
- if (this.blockDataPosition >= this.blockDataBytes)
- readNextBlock();
- return (this.blockData[this.blockDataPosition++] & 0xff);
- }
- else
- return this.realInputStream.read();
- }
- public int read(byte[] data, int offset, int length) throws IOException
- {
- if (this.readDataFromBlock)
- {
- int remain = this.blockDataBytes - this.blockDataPosition;
- if (remain == 0)
- {
- readNextBlock();
- remain = this.blockDataBytes - this.blockDataPosition;
- }
- length = Math.min(length, remain);
- System.arraycopy(this.blockData, this.blockDataPosition,
- data, offset, length);
- this.blockDataPosition += length;
- return length;
- }
- else
- return this.realInputStream.read(data, offset, length);
- }
- public int available() throws IOException
- {
- if (this.readDataFromBlock)
- {
- if (this.blockDataPosition >= this.blockDataBytes)
- readNextBlock ();
- return this.blockDataBytes - this.blockDataPosition;
- }
- else
- return this.realInputStream.available();
- }
- public void close() throws IOException
- {
- this.realInputStream.close();
- }
- public boolean readBoolean() throws IOException
- {
- boolean switchmode = true;
- boolean oldmode = this.readDataFromBlock;
- if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 1)
- switchmode = false;
- if (switchmode)
- oldmode = setBlockDataMode (true);
- boolean value = this.dataInputStream.readBoolean ();
- if (switchmode)
- setBlockDataMode (oldmode);
- return value;
- }
- public byte readByte() throws IOException
- {
- boolean switchmode = true;
- boolean oldmode = this.readDataFromBlock;
- if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 1)
- switchmode = false;
- if (switchmode)
- oldmode = setBlockDataMode(true);
- byte value = this.dataInputStream.readByte();
- if (switchmode)
- setBlockDataMode(oldmode);
- return value;
- }
- public int readUnsignedByte() throws IOException
- {
- boolean switchmode = true;
- boolean oldmode = this.readDataFromBlock;
- if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 1)
- switchmode = false;
- if (switchmode)
- oldmode = setBlockDataMode(true);
- int value = this.dataInputStream.readUnsignedByte();
- if (switchmode)
- setBlockDataMode(oldmode);
- return value;
- }
- public short readShort() throws IOException
- {
- boolean switchmode = true;
- boolean oldmode = this.readDataFromBlock;
- if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 2)
- switchmode = false;
- if (switchmode)
- oldmode = setBlockDataMode(true);
- short value = this.dataInputStream.readShort();
- if (switchmode)
- setBlockDataMode(oldmode);
- return value;
- }
- public int readUnsignedShort() throws IOException
- {
- boolean switchmode = true;
- boolean oldmode = this.readDataFromBlock;
- if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 2)
- switchmode = false;
- if (switchmode)
- oldmode = setBlockDataMode(true);
- int value = this.dataInputStream.readUnsignedShort();
- if (switchmode)
- setBlockDataMode(oldmode);
- return value;
- }
- public char readChar() throws IOException
- {
- boolean switchmode = true;
- boolean oldmode = this.readDataFromBlock;
- if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 2)
- switchmode = false;
- if (switchmode)
- oldmode = setBlockDataMode(true);
- char value = this.dataInputStream.readChar();
- if (switchmode)
- setBlockDataMode(oldmode);
- return value;
- }
- public int readInt() throws IOException
- {
- boolean switchmode = true;
- boolean oldmode = this.readDataFromBlock;
- if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 4)
- switchmode = false;
- if (switchmode)
- oldmode = setBlockDataMode(true);
- int value = this.dataInputStream.readInt();
- if (switchmode)
- setBlockDataMode(oldmode);
- return value;
- }
- public long readLong() throws IOException
- {
- boolean switchmode = true;
- boolean oldmode = this.readDataFromBlock;
- if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 8)
- switchmode = false;
- if (switchmode)
- oldmode = setBlockDataMode(true);
- long value = this.dataInputStream.readLong();
- if (switchmode)
- setBlockDataMode(oldmode);
- return value;
- }
- public float readFloat() throws IOException
- {
- boolean switchmode = true;
- boolean oldmode = this.readDataFromBlock;
- if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 4)
- switchmode = false;
- if (switchmode)
- oldmode = setBlockDataMode(true);
- float value = this.dataInputStream.readFloat();
- if (switchmode)
- setBlockDataMode(oldmode);
- return value;
- }
- public double readDouble() throws IOException
- {
- boolean switchmode = true;
- boolean oldmode = this.readDataFromBlock;
- if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 8)
- switchmode = false;
- if (switchmode)
- oldmode = setBlockDataMode(true);
- double value = this.dataInputStream.readDouble();
- if (switchmode)
- setBlockDataMode(oldmode);
- return value;
- }
- public void readFully(byte data[]) throws IOException
- {
- this.dataInputStream.readFully(data);
- }
- public void readFully(byte data[], int offset, int size)
- throws IOException
- {
- this.dataInputStream.readFully(data, offset, size);
- }
- public int skipBytes(int len) throws IOException
- {
- return this.dataInputStream.skipBytes(len);
- }
- /**
- * @deprecated
- * @see java.io.DataInputStream#readLine ()
- */
- public String readLine() throws IOException
- {
- return this.dataInputStream.readLine();
- }
- public String readUTF() throws IOException
- {
- return this.dataInputStream.readUTF();
- }
- /**
- * This class allows a class to specify exactly which fields should
- * be read, and what values should be read for these fields.
- *
- * XXX: finish up comments
- */
- public abstract static class GetField
- {
- public abstract ObjectStreamClass getObjectStreamClass();
- public abstract boolean defaulted(String name)
- throws IOException, IllegalArgumentException;
- public abstract boolean get(String name, boolean defvalue)
- throws IOException, IllegalArgumentException;
- public abstract char get(String name, char defvalue)
- throws IOException, IllegalArgumentException;
- public abstract byte get(String name, byte defvalue)
- throws IOException, IllegalArgumentException;
- public abstract short get(String name, short defvalue)
- throws IOException, IllegalArgumentException;
- public abstract int get(String name, int defvalue)
- throws IOException, IllegalArgumentException;
- public abstract long get(String name, long defvalue)
- throws IOException, IllegalArgumentException;
- public abstract float get(String name, float defvalue)
- throws IOException, IllegalArgumentException;
- public abstract double get(String name, double defvalue)
- throws IOException, IllegalArgumentException;
- public abstract Object get(String name, Object defvalue)
- throws IOException, IllegalArgumentException;
- }
- /**
- * This method should be called by a method called 'readObject' in the
- * deserializing class (if present). It cannot (and should not)be called
- * outside of it. Its goal is to read all fields in the real input stream
- * and keep them accessible through the {@link GetField} class. Calling
- * this method will not alter the deserializing object.
- *
- * @return A valid freshly created 'GetField' instance to get access to
- * the deserialized stream.
- * @throws IOException An input/output exception occured.
- * @throws ClassNotFoundException
- * @throws NotActiveException
- */
- public GetField readFields()
- throws IOException, ClassNotFoundException, NotActiveException
- {
- if (this.currentObject == null || this.currentObjectStreamClass == null)
- throw new NotActiveException("readFields called by non-active class and/or object");
- if (prereadFields != null)
- return prereadFields;
- if (fieldsAlreadyRead)
- throw new NotActiveException("readFields called but fields already read from"
- + " stream (by defaultReadObject or readFields)");
- final ObjectStreamClass clazz = this.currentObjectStreamClass;
- final byte[] prim_field_data = new byte[clazz.primFieldSize];
- final Object[] objs = new Object[clazz.objectFieldCount];
- // Apparently Block data is not used with GetField as per
- // empirical evidence against JDK 1.2. Also see Mauve test
- // java.io.ObjectInputOutput.Test.GetPutField.
- boolean oldmode = setBlockDataMode(false);
- readFully(prim_field_data);
- for (int i = 0; i < objs.length; ++ i)
- objs[i] = readObject();
- setBlockDataMode(oldmode);
- prereadFields = new GetField()
- {
- public ObjectStreamClass getObjectStreamClass()
- {
- return clazz;
- }
- public boolean defaulted(String name)
- throws IOException, IllegalArgumentException
- {
- ObjectStreamField f = clazz.getField(name);
- /* First if we have a serialized field use the descriptor */
- if (f != null)
- {
- /* It is in serialPersistentFields but setClass tells us
- * it should not be set. This value is defaulted.
- */
- if (f.isPersistent() && !f.isToSet())
- return true;
- return false;
- }
- /* This is not a serialized field. There should be
- * a default value only if the field really exists.
- */
- try
- {
- return (clazz.forClass().getDeclaredField (name) != null);
- }
- catch (NoSuchFieldException e)
- {
- throw new IllegalArgumentException(e);
- }
- }
- public boolean get(String name, boolean defvalue)
- throws IOException, IllegalArgumentException
- {
- ObjectStreamField field = getField(name, Boolean.TYPE);
- if (field == null)
- return defvalue;
- return prim_field_data[field.getOffset()] == 0 ? false : true;
- }
- public char get(String name, char defvalue)
- throws IOException, IllegalArgumentException
- {
- ObjectStreamField field = getField(name, Character.TYPE);
- if (field == null)
- return defvalue;
- int off = field.getOffset();
- return (char)(((prim_field_data[off++] & 0xFF) << 8)
- | (prim_field_data[off] & 0xFF));
- }
- public byte get(String name, byte defvalue)
- throws IOException, IllegalArgumentException
- {
- ObjectStreamField field = getField(name, Byte.TYPE);
- if (field == null)
- return defvalue;
- return prim_field_data[field.getOffset()];
- }
- public short get(String name, short defvalue)
- throws IOException, IllegalArgumentException
- {
- ObjectStreamField field = getField(name, Short.TYPE);
- if (field == null)
- return defvalue;
- int off = field.getOffset();
- return (short)(((prim_field_data[off++] & 0xFF) << 8)
- | (prim_field_data[off] & 0xFF));
- }
- public int get(String name, int defvalue)
- throws IOException, IllegalArgumentException
- {
- ObjectStreamField field = getField(name, Integer.TYPE);
- if (field == null)
- return defvalue;
- int off = field.getOffset();
- return ((prim_field_data[off++] & 0xFF) << 24)
- | ((prim_field_data[off++] & 0xFF) << 16)
- | ((prim_field_data[off++] & 0xFF) << 8)
- | (prim_field_data[off] & 0xFF);
- }
- public long get(String name, long defvalue)
- throws IOException, IllegalArgumentException
- {
- ObjectStreamField field = getField(name, Long.TYPE);
- if (field == null)
- return defvalue;
- int off = field.getOffset();
- return (long)(((prim_field_data[off++] & 0xFFL) << 56)
- | ((prim_field_data[off++] & 0xFFL) << 48)
- | ((prim_field_data[off++] & 0xFFL) << 40)
- | ((prim_field_data[off++] & 0xFFL) << 32)
- | ((prim_field_data[off++] & 0xFF) << 24)
- | ((prim_field_data[off++] & 0xFF) << 16)
- | ((prim_field_data[off++] & 0xFF) << 8)
- | (prim_field_data[off] & 0xFF));
- }
- public float get(String name, float defvalue)
- throws IOException, IllegalArgumentException
- {
- ObjectStreamField field = getField(name, Float.TYPE);
- if (field == null)
- return defvalue;
- int off = field.getOffset();
- return Float.intBitsToFloat(((prim_field_data[off++] & 0xFF) << 24)
- | ((prim_field_data[off++] & 0xFF) << 16)
- | ((prim_field_data[off++] & 0xFF) << 8)
- | (prim_field_data[off] & 0xFF));
- }
- public double get(String name, double defvalue)
- throws IOException, IllegalArgumentException
- {
- ObjectStreamField field = getField(name, Double.TYPE);
- if (field == null)
- return defvalue;
- int off = field.getOffset();
- return Double.longBitsToDouble
- ( (long) (((prim_field_data[off++] & 0xFFL) << 56)
- | ((prim_field_data[off++] & 0xFFL) << 48)
- | ((prim_field_data[off++] & 0xFFL) << 40)
- | ((prim_field_data[off++] & 0xFFL) << 32)
- | ((prim_field_data[off++] & 0xFF) << 24)
- | ((prim_field_data[off++] & 0xFF) << 16)
- | ((prim_field_data[off++] & 0xFF) << 8)
- | (prim_field_data[off] & 0xFF)));
- }
- public Object get(String name, Object defvalue)
- throws IOException, IllegalArgumentException
- {
- ObjectStreamField field =
- getField(name, defvalue == null ? null : defvalue.getClass ());
- if (field == null)
- return defvalue;
- return objs[field.getOffset()];
- }
- private ObjectStreamField getField(String name, Class type)
- throws IllegalArgumentException
- {
- ObjectStreamField field = clazz.getField(name);
- boolean illegal = false;
- // XXX This code is horrible and needs to be rewritten!
- try
- {
- try
- {
- Class field_type = field.getType();
- if (type == field_type ||
- (type == null && !field_type.isPrimitive()))
- {
- /* See defaulted */
- return field;
- }
- illegal = true;
- throw new IllegalArgumentException
- ("Field requested is of type "
- + field_type.getName()
- + ", but requested type was "
- + (type == null ? "Object" : type.getName()));
- }
- catch (NullPointerException _)
- {
- /* Here we catch NullPointerException, because it may
- only come from the call 'field.getType()'. If field
- is null, we have to return null and classpath ethic
- say we must try to avoid 'if (xxx == null)'.
- */
- }
- catch (IllegalArgumentException e)
- {
- throw e;
- }
- return null;
- }
- finally
- {
- /* If this is an unassigned field we should return
- * the default value.
- */
- if (!illegal && field != null && !field.isToSet() && field.isPersistent())
- return null;
- /* We do not want to modify transient fields. They should
- * be left to 0.
- */
- try
- {
- Field f = clazz.forClass().getDeclaredField(name);
- if (Modifier.isTransient(f.getModifiers()))
- throw new IllegalArgumentException
- ("no such field (non transient) " + name);
- if (field == null && f.getType() != type)
- throw new IllegalArgumentException
- ("Invalid requested type for field " + name);
- }
- catch (NoSuchFieldException e)
- {
- if (field == null)
- throw new IllegalArgumentException(e);
- }
- }
- }
- };
- fieldsAlreadyRead = true;
- return prereadFields;
- }
- /**
- * Protected constructor that allows subclasses to override
- * deserialization. This constructor should be called by subclasses
- * that wish to override <code>readObject (Object)</code>. This
- * method does a security check <i>NOTE: currently not
- * implemented</i>, then sets a flag that informs
- * <code>readObject (Object)</code> to call the subclasses
- * <code>readObjectOverride (Object)</code> method.
- *
- * @see #readObjectOverride()
- */
- protected ObjectInputStream()
- throws IOException, SecurityException
- {
- SecurityManager sec_man = System.getSecurityManager();
- if (sec_man != null)
- sec_man.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
- this.useSubclassMethod = true;
- }
- /**
- * This method allows subclasses to override the default
- * de serialization mechanism provided by
- * <code>ObjectInputStream</code>. To make this method be used for
- * writing objects, subclasses must invoke the 0-argument
- * constructor on this class from their constructor.
- *
- * @see #ObjectInputStream()
- */
- protected Object readObjectOverride()
- throws ClassNotFoundException, IOException, OptionalDataException
- {
- throw new IOException("Subclass of ObjectInputStream must implement readObjectOverride");
- }
- /**
- * Assigns the next available handle to <code>obj</code>.
- *
- * @param obj The object for which we want a new handle.
- * @param shared True if the handle should be shared
- * with later calls.
- * @return A valid handle for the specified object.
- */
- private int assignNewHandle(Object obj, boolean shared)
- {
- int handle = this.nextOID;
- this.nextOID = handle + 1;
- rememberHandle(obj,shared,handle);
- return handle;
- }
- /**
- * Remember the object associated with the given handle.
- *
- * @param obj an object
- * @param shared true if the reference should be shared
- * with later calls.
- * @param handle a handle, must be >= baseWireHandle
- *
- * @see #lookupHandle
- */
- private void rememberHandle(Object obj, boolean shared,
- int handle)
- {
- handles.put(handle, new Pair<Boolean,Object>(shared, obj));
- }
- /**
- * Look up the object associated with a given handle.
- *
- * @param handle a handle, must be >= baseWireHandle
- * @return the object remembered for handle or null if none.
- * @throws StreamCorruptedException if the handle is invalid.
- * @throws InvalidObjectException if the reference is not shared.
- * @see #rememberHandle
- */
- private Object lookupHandle(int handle)
- throws ObjectStreamException
- {
- Pair<Boolean,Object> result = handles.get(handle);
- if (result == null)
- throw new StreamCorruptedException("The handle, " +
- Integer.toHexString(handle) +
- ", is invalid.");
- if (!result.getLeft())
- throw new InvalidObjectException("The handle, " +
- Integer.toHexString(handle) +
- ", is not shared.");
- return result.getRight();
- }
- private Object processResolution(ObjectStreamClass osc, Object obj, int handle,
- boolean shared)
- throws IOException
- {
- if (osc != null && obj instanceof Serializable)
- {
- try
- {
- Method m = osc.readResolveMethod;
- if(m != null)
- {
- obj = m.invoke(obj, new Object[] {});
- }
- }
- catch (IllegalAccessException ignore)
- {
- }
- catch (InvocationTargetException exception)
- {
- Throwable cause = exception.getCause();
- if (cause instanceof ObjectStreamException)
- throw (ObjectStreamException) cause;
- else if (cause instanceof RuntimeException)
- throw (RuntimeException) cause;
- else if (cause instanceof Error)
- throw (Error) cause;
- }
- }
- if (this.resolveEnabled)
- obj = resolveObject(obj);
- rememberHandle(obj, shared, handle);
- if (!shared)
- {
- if (obj instanceof byte[])
- return ((byte[]) obj).clone();
- if (obj instanceof short[])
- return ((short[]) obj).clone();
- if (obj instanceof int[])
- return ((int[]) obj).clone();
- if (obj instanceof long[])
- return ((long[]) obj).clone();
- if (obj instanceof char[])
- return ((char[]) obj).clone();
- if (obj instanceof boolean[])
- return ((boolean[]) obj).clone();
- if (obj instanceof float[])
- return ((float[]) obj).clone();
- if (obj instanceof double[])
- return ((double[]) obj).clone();
- if (obj instanceof Object[])
- return ((Object[]) obj).clone();
- }
- return obj;
- }
- private void clearHandles()
- {
- handles.clear();
- this.nextOID = baseWireHandle;
- }
- private void readNextBlock() throws IOException
- {
- byte marker = this.realInputStream.readByte();
- while (marker == TC_RESET)
- {
- if(dump) dumpElementln("RESET");
- clearHandles();
- marker = this.realInputStream.readByte();
- }
- readNextBlock(marker);
- }
- private void readNextBlock(byte marker) throws IOException
- {
- if (marker == TC_BLOCKDATA)
- {
- if(dump) dumpElement("BLOCK DATA SIZE=");
- this.blockDataBytes = this.realInputStream.readUnsignedByte();
- if(dump) dumpElementln (Integer.toString(this.blockDataBytes));
- }
- else if (marker == TC_BLOCKDATALONG)
- {
- if(dump) dumpElement("BLOCK DATA LONG SIZE=");
- this.blockDataBytes = this.realInputStream.readInt();
- if(dump) dumpElementln (Integer.toString(this.blockDataBytes));
- }
- else
- {
- throw new EOFException("Attempt to read primitive data, but no data block is active.");
- }
- if (this.blockData.length < this.blockDataBytes)
- this.blockData = new byte[this.blockDataBytes];
- this.realInputStream.readFully (this.blockData, 0, this.blockDataBytes);
- this.blockDataPosition = 0;
- }
- private void readArrayElements (Object array, Class clazz)
- throws ClassNotFoundException, IOException
- {
- if (clazz.isPrimitive())
- {
- if (clazz == Boolean.TYPE)
- {
- boolean[] cast_array = (boolean[])array;
- for (int i=0; i < cast_array.length; i++)
- cast_array[i] = this.realInputStream.readBoolean();
- return;
- }
- if (clazz == Byte.TYPE)
- {
- byte[] cast_array = (byte[])array;
- for (int i=0; i < cast_array.length; i++)
- cast_array[i] = this.realInputStream.readByte();
- return;
- }
- if (clazz == Character.TYPE)
- {
- char[] cast_array = (char[])array;
- for (int i=0; i < cast_array.length; i++)
- cast_array[i] = this.realInputStream.readChar();
- return;
- }
- if (clazz == Double.TYPE)
- {
- double[] cast_array = (double[])array;
- for (int i=0; i < cast_array.length; i++)
- cast_array[i] = this.realInputStream.readDouble();
- return;
- }
- if (clazz == Float.TYPE)
- {
- float[] cast_array = (float[])array;
- for (int i=0; i < cast_array.length; i++)
- cast_array[i] = this.realInputStream.readFloat();
- return;
- }
- if (clazz == Integer.TYPE)
- {
- int[] cast_array = (int[])array;
- for (int i=0; i < cast_array.length; i++)
- cast_array[i] = this.realInputStream.readInt();
- return;
- }
- if (clazz == Long.TYPE)
- {
- long[] cast_array = (long[])array;
- for (int i=0; i < cast_array.length; i++)
- cast_array[i] = this.realInputStream.readLong();
- return;
- }
- if (clazz == Short.TYPE)
- {
- short[] cast_array = (short[])array;
- for (int i=0; i < cast_array.length; i++)
- cast_array[i] = this.realInputStream.readShort();
- return;
- }
- }
- else
- {
- Object[] cast_array = (Object[])array;
- for (int i=0; i < cast_array.length; i++)
- cast_array[i] = readObject();
- }
- }
- private void readFields (Object obj, ObjectStreamClass stream_osc)
- throws ClassNotFoundException, IOException
- {
- ObjectStreamField[] fields = stream_osc.fieldMapping;
- for (int i = 0; i < fields.length; i += 2)
- {
- ObjectStreamField stream_field = fields[i];
- ObjectStreamField real_field = fields[i + 1];
- boolean read_value = (stream_field != null && stream_field.getOffset() >= 0 && stream_field.isToSet());
- boolean set_value = (real_field != null && real_field.isToSet());
- String field_name;
- char type;
- if (stream_field != null)
- {
- field_name = stream_field.getName();
- type = stream_field.getTypeCode();
- }
- else
- {
- field_name = real_field.getName();
- type = real_field.getTypeCode();
- }
- switch(type)
- {
- case 'Z':
- {
- boolean value =
- read_value ? this.realInputStream.readBoolean() : false;
- if (dump && read_value && set_value)
- dumpElementln(" " + field_name + ": " + value);
- if (set_value)
- real_field.setBooleanField(obj, value);
- break;
- }
- case 'B':
- {
- byte value =
- read_value ? this.realInputStream.readByte() : 0;
- if (dump && read_value && set_value)
- dumpElementln(" " + field_name + ": " + value);
- if (set_value)
- real_field.setByteField(obj, value);
- break;
- }
- case 'C':
- {
- char value =
- read_value ? this.realInputStream.readChar(): 0;
- if (dump && read_value && set_value)
- dumpElementln(" " + field_name + ": " + value);
- if (set_value)
- real_field.setCharField(obj, value);
- break;
- }
- case 'D':
- {
- double value =
- read_value ? this.realInputStream.readDouble() : 0;
- if (dump && read_value && set_value)
- dumpElementln(" " + field_name + ": " + value);
- if (set_value)
- real_field.setDoubleField(obj, value);
- break;
- }
- case 'F':
- {
- float value =
- read_value ? this.realInputStream.readFloat() : 0;
- if (dump && read_value && set_value)
- dumpElementln(" " + field_name + ": " + value);
- if (set_value)
- real_field.setFloatField(obj, value);
- break;
- }
- case 'I':
- {
- int value =
- read_value ? this.realInputStream.readInt() : 0;
- if (dump && read_value && set_value)
- dumpElementln(" " + field_name + ": " + value);
- if (set_value)
- real_field.setIntField(obj, value);
- break;
- }
- case 'J':
- {
- long value =
- read_value ? this.realInputStream.readLong() : 0;
- if (dump && read_value && set_value)
- dumpElementln(" " + field_name + ": " + value);
- if (set_value)
- real_field.setLongField(obj, value);
- break;
- }
- case 'S':
- {
- short value =
- read_value ? this.realInputStream.readShort() : 0;
- if (dump && read_value && set_value)
- dumpElementln(" " + field_name + ": " + value);
- if (set_value)
- real_field.setShortField(obj, value);
- break;
- }
- case 'L':
- case '[':
- {
- Object value =
- read_value ? readObject() : null;
- if (set_value)
- real_field.setObjectField(obj, value);
- break;
- }
- default:
- throw new InternalError("Invalid type code: " + type);
- }
- }
- }
- // Toggles writing primitive data to block-data buffer.
- private boolean setBlockDataMode (boolean on)
- {
- boolean oldmode = this.readDataFromBlock;
- this.readDataFromBlock = on;
- if (on)
- this.dataInputStream = this.blockDataInput;
- else
- this.dataInputStream = this.realInputStream;
- return oldmode;
- }
- // returns a new instance of REAL_CLASS that has been constructed
- // only to the level of CONSTRUCTOR_CLASS (a super class of REAL_CLASS)
- private Object newObject (Class real_class, Constructor constructor)
- throws ClassNotFoundException, IOException
- {
- if (constructor == null)
- throw new InvalidClassException("Missing accessible no-arg base class constructor for " + real_class.getName());
- try
- {
- return VMObjectInputStream.allocateObject(real_class, constructor.getDeclaringClass(), constructor);
- }
- catch (InstantiationException e)
- {
- throw (ClassNotFoundException) new ClassNotFoundException
- ("Instance of " + real_class + " could not be created").initCause(e);
- }
- }
- // runs all registered ObjectInputValidations in prioritized order
- // on OBJ
- private void invokeValidators() throws InvalidObjectException
- {
- try
- {
- Iterator<ValidatorAndPriority> it = currentObjectValidators.iterator();
- while(it.hasNext())
- {
- ValidatorAndPriority vap = it.next();
- ObjectInputValidation validator = vap.validator;
- validator.validateObject();
- }
- }
- finally
- {
- currentObjectValidators = null;
- }
- }
- private void callReadMethod (Method readObject, Class klass, Object obj)
- throws ClassNotFoundException, IOException
- {
- try
- {
- readObject.invoke(obj, new Object[] { this });
- }
- catch (InvocationTargetException x)
- {
- /* Rethrow if possible. */
- Throwable exception = x.getTargetException();
- if (exception instanceof RuntimeException)
- throw (RuntimeException) exception;
- if (exception instanceof IOException)
- throw (IOException) exception;
- if (exception instanceof ClassNotFoundException)
- throw (ClassNotFoundException) exception;
- throw (IOException) new IOException(
- "Exception thrown from readObject() on " + klass).initCause(x);
- }
- catch (Exception x)
- {
- throw (IOException) new IOException(
- "Failure invoking readObject() on " + klass).initCause(x);
- }
- // Invalidate fields which has been read through readFields.
- prereadFields = null;
- }
- private static final int BUFFER_SIZE = 1024;
- private DataInputStream realInputStream;
- private DataInputStream dataInputStream;
- private DataInputStream blockDataInput;
- private int blockDataPosition;
- private int blockDataBytes;
- private byte[] blockData;
- private boolean useSubclassMethod;
- private int nextOID;
- private boolean resolveEnabled;
- private Map<Integer,Pair<Boolean,Object>> handles;
- private Object currentObject;
- private ObjectStreamClass currentObjectStreamClass;
- private TreeSet<ValidatorAndPriority> currentObjectValidators;
- private boolean readDataFromBlock;
- private boolean fieldsAlreadyRead;
- private Hashtable<Class,ObjectStreamClass> classLookupTable;
- private GetField prereadFields;
- private static boolean dump;
- // The nesting depth for debugging output
- private int depth = 0;
- private static final boolean DEBUG = false;
- private void dumpElement (String msg)
- {
- System.out.print(msg);
- }
- private void dumpElementln (String msg)
- {
- System.out.println(msg);
- for (int i = 0; i < depth; i++)
- System.out.print (" ");
- System.out.print (Thread.currentThread() + ": ");
- }
- private void dumpElementln (String msg, Object obj)
- {
- try
- {
- System.out.print(msg);
- if (java.lang.reflect.Proxy.isProxyClass(obj.getClass()))
- System.out.println(obj.getClass());
- else
- System.out.println(obj);
- }
- catch (Exception _)
- {
- }
- for (int i = 0; i < depth; i++)
- System.out.print (" ");
- System.out.print (Thread.currentThread() + ": ");
- }
- // used to keep a prioritized list of object validators
- private static final class ValidatorAndPriority implements Comparable
- {
- int priority;
- ObjectInputValidation validator;
- ValidatorAndPriority (ObjectInputValidation validator, int priority)
- {
- this.priority = priority;
- this.validator = validator;
- }
- public int compareTo (Object o)
- {
- ValidatorAndPriority vap = (ValidatorAndPriority)o;
- return this.priority - vap.priority;
- }
- }
- }
|