📄 objectinputstream.java
字号:
/* ObjectInputStream.java -- Class used to read serialized objects Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2005 Free Software Foundation, Inc.This file is part of GNU Classpath.GNU Classpath is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe 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, butWITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNUGeneral Public License for more details.You should have received a copy of the GNU General Public Licensealong with GNU Classpath; see the file COPYING. If not, write to theFree Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA02110-1301 USA.Linking this library statically or dynamically with other modules ismaking a combined work based on this library. Thus, the terms andconditions of the GNU General Public License cover the wholecombination.As a special exception, the copyright holders of this library give youpermission to link this library with independent modules to produce anexecutable, regardless of the license terms of these independentmodules, and to copy and distribute the resulting executable underterms of your choice, provided that you also meet, for each linkedindependent module, the terms and conditions of the license of thatmodule. An independent module is a module which is not derived fromor based on this library. If you modify this library, you may extendthis exception to your version of the library, but you are notobligated to do so. If you do not wish to do so, delete thisexception statement from your version. */package java.io;import gnu.classpath.Configuration;import gnu.java.io.ObjectIdentityWrapper;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.Arrays;import java.util.Hashtable;import java.util.Vector;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 (Configuration.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.isDeserializing = 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; this.objectLookupTable = new Hashtable(); this.validators = new Vector(); this.classLookupTable = new Hashtable(); 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 { if (this.useSubclassMethod) return readObjectOverride(); boolean was_deserializing; Object ret_val; was_deserializing = this.isDeserializing; boolean is_consumed = false; boolean old_mode = setBlockDataMode(false); this.isDeserializing = true; byte marker = this.realInputStream.readByte(); depth += 2; if(dump) dumpElement("MARKER: 0x" + Integer.toHexString(marker) + " "); try { 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); throw new StreamCorruptedException("Unexpected blockData"); } case TC_NULL: { if(dump) dumpElementln("NULL"); ret_val = null; break; } case TC_REFERENCE: { if(dump) dumpElement("REFERENCE "); Integer oid = new Integer(this.realInputStream.readInt()); if(dump) dumpElementln(Integer.toHexString(oid.intValue())); ret_val = ((ObjectIdentityWrapper) this.objectLookupTable.get(oid)).object; break; } case TC_CLASS: { if(dump) dumpElementln("CLASS"); ObjectStreamClass osc = (ObjectStreamClass)readObject(); Class clazz = osc.forClass(); assignNewHandle(clazz); ret_val = clazz; break; } case TC_PROXYCLASSDESC: { if(dump) dumpElementln("PROXYCLASS"); 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); } } assignNewHandle(osc); 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: case TC_LONGSTRING: { if(dump) dumpElement("STRING="); String s = this.realInputStream.readUTF(); if(dump) dumpElementln(s); ret_val = processResolution(null, s, assignNewHandle(s)); 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); 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); 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); 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); break; } // end if (osc.realClassIsExternalizable) Object obj = newObject(clazz, osc.firstNonSerializableParentConstructor); int handle = assignNewHandle(obj); Object prevObject = this.currentObject; ObjectStreamClass prevObjectStreamClass = this.currentObjectStreamClass; this.currentObject = obj; ObjectStreamClass[] hierarchy = inputGetObjectStreamClasses(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 { // FIXME: XXX: This try block is to // catch EOF which is thrown for some // objects. That indicates a bug in // the logic. if (this.realInputStream.readByte() != TC_ENDBLOCKDATA) throw new IOException ("No end of block data seen for class with readObject (ObjectInputStream) method."); if(dump) dumpElementln("yes"); }// catch (EOFException e)// {// if(dump) dumpElementln("no, got EOFException");// } catch (IOException e) { if(dump) dumpElementln("no, got IOException"); } } } this.currentObject = prevObject; this.currentObjectStreamClass = prevObjectStreamClass; ret_val = processResolution(osc, obj, handle); 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); } default: throw new IOException("Unknown marker on stream: " + marker); } } finally { setBlockDataMode(old_mode); this.isDeserializing = was_deserializing; depth -= 2; if (! was_deserializing) { if (validators.size() > 0) invokeValidators(); } } 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. *
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -