private Object readObject0(boolean unshared)throws IOException { boolean oldMode = bin.getBlockDataMode(); if (oldMode) { int remain = bin.currentBlockRemaining(); if (remain > 0) { thrownew OptionalDataException(remain); } elseif (defaultDataEnd) { /* * Fix for 4360508: stream is currently at the end of a field * value block written via default serialization; since there * is no terminating TC_ENDBLOCKDATA tag, simulate * end-of-custom-data behavior explicitly. */ thrownew OptionalDataException(true); } bin.setBlockDataMode(false); }
depth++; try { switch (tc) { case TC_NULL: return readNull();
case TC_REFERENCE: return readHandle(unshared);
case TC_CLASS: return readClass(unshared);
case TC_CLASSDESC: case TC_PROXYCLASSDESC: return readClassDesc(unshared);
case TC_STRING: case TC_LONGSTRING: return checkResolve(readString(unshared));
case TC_ARRAY: return checkResolve(readArray(unshared));
case TC_ENUM: return checkResolve(readEnum(unshared));
case TC_OBJECT: return checkResolve(readOrdinaryObject(unshared));
case TC_EXCEPTION: IOException ex = readFatalException(); thrownew WriteAbortedException("writing aborted", ex);
case TC_BLOCKDATA: case TC_BLOCKDATALONG: if (oldMode) { bin.setBlockDataMode(true); bin.peek(); // force header read thrownew OptionalDataException( bin.currentBlockRemaining()); } else { thrownew StreamCorruptedException( "unexpected block data"); }
case TC_ENDBLOCKDATA: if (oldMode) { thrownew OptionalDataException(true); } else { thrownew StreamCorruptedException( "unexpected end of block data"); }
private Object readHandle(boolean unshared)throws IOException { if (bin.readByte() != TC_REFERENCE) { thrownew InternalError(); } passHandle = bin.readInt() - baseWireHandle; if (passHandle < 0 || passHandle >= handles.size()) { thrownew StreamCorruptedException( String.format("invalid handle value: %08X", passHandle + baseWireHandle)); } if (unshared) { // REMIND: what type of exception to throw here? thrownew InvalidObjectException( "cannot read back reference as unshared"); }
Object obj = handles.lookupObject(passHandle); if (obj == unsharedMarker) { // REMIND: what type of exception to throw here? thrownew InvalidObjectException( "cannot read back reference to unshared object"); } return obj; }
ObjectStreamClass desc = new ObjectStreamClass(); int descHandle = handles.assign(unshared ? unsharedMarker : desc); passHandle = NULL_HANDLE;
int numIfaces = bin.readInt(); String[] ifaces = new String[numIfaces]; for (int i = 0; i < numIfaces; i++) { ifaces[i] = bin.readUTF(); }
Class cl = null; ClassNotFoundException resolveEx = null; bin.setBlockDataMode(true); try { if ((cl = resolveProxyClass(ifaces)) == null) { resolveEx = new ClassNotFoundException("null class"); } elseif (!Proxy.isProxyClass(cl)) { thrownew InvalidClassException("Not a proxy"); } else { // ReflectUtil.checkProxyPackageAccess makes a test // equivalent to isCustomSubclass so there's no need // to condition this call to isCustomSubclass == true here. ReflectUtil.checkProxyPackageAccess(getClass().getClassLoader(), cl.getInterfaces()); } } catch (ClassNotFoundException ex) { resolveEx = ex; } skipCustomData();
privatevoidskipCustomData()throws IOException { int oldHandle = passHandle; for (;;) { if (bin.getBlockDataMode()) { bin.skipBlockData(); bin.setBlockDataMode(false); } switch (bin.peekByte()) { case TC_BLOCKDATA: case TC_BLOCKDATALONG: bin.setBlockDataMode(true); break;
case TC_ENDBLOCKDATA: bin.readByte(); passHandle = oldHandle; return;
int enumHandle = handles.assign(unshared ? unsharedMarker : null); ClassNotFoundException resolveEx = desc.getResolveException(); if (resolveEx != null) { handles.markException(enumHandle, resolveEx); }
String name = readString(false); Enum en = null; Class cl = desc.forClass(); if (cl != null) { try { en = Enum.valueOf(cl, name); } catch (IllegalArgumentException ex) { throw (IOException) new InvalidObjectException("enum constant " + name + " does not exist in " + cl).initCause(ex); } if (!unshared) { handles.setObject(enumHandle, en); } }
privatevoidreadExternalData(Externalizable obj, ObjectStreamClass desc) throws IOException { SerialCallbackContext oldContext = curContext; curContext = null; try { boolean blocked = desc.hasBlockExternalData(); if (blocked) { bin.setBlockDataMode(true); } if (obj != null) { try { obj.readExternal(this); } catch (ClassNotFoundException ex) { /* * In most cases, the handle table has already propagated * a CNFException to passHandle at this point; this mark * call is included to address cases where the readExternal * method has cons'ed and thrown a new CNFException of its * own. */ handles.markException(passHandle, ex); } } if (blocked) { skipCustomData(); } } finally { curContext = oldContext; } /* * At this point, if the externalizable data was not written in * block-data form and either the externalizable class doesn't exist * locally (i.e., obj == null) or readExternal() just threw a * CNFException, then the stream is probably in an inconsistent state, * since some (or all) of the externalizable data may not have been * consumed. Since there's no "correct" action to take in this case, * we mimic the behavior of past serialization implementations and * blindly hope that the stream is in sync; if it isn't and additional * externalizable data remains in the stream, a subsequent read will * most likely throw a StreamCorruptedException. */ }
privatevoidreadSerialData(Object obj, ObjectStreamClass desc) throws IOException { ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout(); for (int i = 0; i < slots.length; i++) { ObjectStreamClass slotDesc = slots[i].desc;
if (slots[i].hasData) { if (obj != null && slotDesc.hasReadObjectMethod() && handles.lookupException(passHandle) == null) { SerialCallbackContext oldContext = curContext;
try { curContext = new SerialCallbackContext(obj, slotDesc);
bin.setBlockDataMode(true); slotDesc.invokeReadObject(obj, this); } catch (ClassNotFoundException ex) { /* * In most cases, the handle table has already * propagated a CNFException to passHandle at this * point; this mark call is included to address cases * where the custom readObject method has cons'ed and * thrown a new CNFException of its own. */ handles.markException(passHandle, ex); } finally { curContext.setUsed(); curContext = oldContext; }
/* * defaultDataEnd may have been set indirectly by custom * readObject() method when calling defaultReadObject() or * readFields(); clear it to restore normal read behavior. */ defaultDataEnd = false; } else { defaultReadFields(obj, slotDesc); } if (slotDesc.hasWriteObjectData()) { skipCustomData(); } else { bin.setBlockDataMode(false); } } else { if (obj != null && slotDesc.hasReadObjectNoDataMethod() && handles.lookupException(passHandle) == null) { slotDesc.invokeReadObjectNoData(obj); } } } }
publicvoiddefaultReadObject()throws IOException, ClassNotFoundException { SerialCallbackContext ctx = curContext; if (ctx == null) { thrownew NotActiveException("not in call to readObject"); } Object curObj = ctx.getObj(); ObjectStreamClass curDesc = ctx.getDesc(); bin.setBlockDataMode(false); defaultReadFields(curObj, curDesc); bin.setBlockDataMode(true); if (!curDesc.hasWriteObjectData()) { /* * Fix for 4360508: since stream does not contain terminating * TC_ENDBLOCKDATA tag, set flag so that reading code elsewhere * knows to simulate end-of-custom-data behavior. */ defaultDataEnd = true; } ClassNotFoundException ex = handles.lookupException(passHandle); if (ex != null) { throw ex; } }
public ObjectInputStream.GetField readFields() throws IOException, ClassNotFoundException { SerialCallbackContext ctx = curContext; if (ctx == null) { thrownew NotActiveException("not in call to readObject"); } Object curObj = ctx.getObj(); ObjectStreamClass curDesc = ctx.getDesc(); bin.setBlockDataMode(false); GetFieldImpl getField = new GetFieldImpl(curDesc); getField.readFields(); bin.setBlockDataMode(true); if (!curDesc.hasWriteObjectData()) { /* * Fix for 4360508: since stream does not contain terminating * TC_ENDBLOCKDATA tag, set flag so that reading code elsewhere * knows to simulate end-of-custom-data behavior. */ defaultDataEnd = true; }
return getField; }
从流中读取字段变量值(基础数据类型和对象类型),并返回一个GetField实例。
public void registerValidation(ObjectInputValidation obj, int prio)
1 2 3 4 5 6 7
publicvoidregisterValidation(ObjectInputValidation obj, int prio) throws NotActiveException, InvalidObjectException { if (depth == 0) { thrownew NotActiveException("stream inactive"); } vlist.register(obj, prio); }
privatebooleanisCustomSubclass(){ // Return true if this class is a custom subclass of ObjectInputStream return getClass().getClassLoader() != ObjectInputStream.class.getClassLoader(); }
如果当前类是ObjectInputStream的一个定制子类实现,那么返回true。
private static native void bytesToFloats(byte[] src, int srcpos, float[] dst, int dstpos, int nfloats);
1 2 3
privatestaticnativevoidbytesToFloats(byte[] src, int srcpos, float[] dst, int dstpos, int nfloats);
完成byte向float的转换。native方法,由系统提供并完成处理。
private static native void bytesToDoubles(byte[] src, int srcpos, double[] dst, int dstpos, int ndoubles);
1 2 3
privatestaticnativevoidbytesToDoubles(byte[] src, int srcpos, double[] dst, int dstpos, int ndoubles);
完成byte向double的转换。native方法,由系统提供并完成处理。
涉及基础知识点
Graphs of objects are restored correctly using a reference sharing mechanism.