📄 objectinputstream.java
字号:
* @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); if (callersClassLoader == null) callersClassLoader = currentLoader(); 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, callersClassLoader); } /* Now that fields have been read we may resolve the class * (and read annotation if needed). */ Class clazz; try { clazz = resolveClass(osc); } catch (ClassNotFoundException cnfe) { // Maybe it was an primitive class? if (name.equals("void")) clazz = Void.TYPE; else if (name.equals("boolean")) clazz = Boolean.TYPE; else if (name.equals("byte")) clazz = Byte.TYPE; else if (name.equals("short")) clazz = Short.TYPE; else if (name.equals("char")) clazz = Character.TYPE; else if (name.equals("int")) clazz = Integer.TYPE; else if (name.equals("long")) clazz = Long.TYPE; else if (name.equals("float")) clazz = Float.TYPE; else if (name.equals("double")) clazz = Double.TYPE; else throw cnfe; } boolean oldmode = setBlockDataMode(true); osc.setClass(clazz, lookupClass(clazz.getSuperclass())); classLookupTable.put(clazz, osc); setBlockDataMode(oldmode); // find the first non-serializable, non-abstract // 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) || Modifier.isAbstract(first_nonserial.getModifiers())) 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"); this.validators.addElement(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 { if (callersClassLoader == null) { callersClassLoader = currentLoader (); if (Configuration.DEBUG && dump) { dumpElementln ("CallersClassLoader = " + callersClassLoader); } } return Class.forName(osc.getName(), true, callersClassLoader); } /** * Returns the most recent user defined ClassLoader on the execution stack * or null if none is found. */ // GCJ LOCAL: native method. private native ClassLoader currentLoader(); /** * 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 = (ObjectStreamClass)classLookupTable.get(clazz); if (oclazz == null) return ObjectStreamClass.lookup(clazz); else return oclazz; } /** * Reconstruct class hierarchy the same way * {@link java.io.ObjectStreamClass.getObjectStreamClasses(java.lang.Class)} does * but using lookupClass instead of ObjectStreamClass.lookup. This * dup is necessary localize the lookup table. Hopefully some future * rewritings will be able to prevent this. * * @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[] inputGetObjectStreamClasses(Class clazz) { ObjectStreamClass osc = lookupClass(clazz); if (osc == null) return new ObjectStreamClass[0]; else { Vector oscs = new Vector(); while (osc != null) { oscs.addElement(osc); osc = osc.getSuper(); } int count = oscs.size(); ObjectStreamClass[] sorted_oscs = new ObjectStreamClass[count]; for (int i = count - 1; i >= 0; i--) sorted_oscs[count - i - 1] = (ObjectStreamClass) oscs.elementAt(i); return sorted_oscs; } } /** * 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] = cl.loadClass(intfs[i]); 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) { if (this.blockDataPosition + length > this.blockDataBytes) { int remain = this.blockDataBytes - this.blockDataPosition; if (remain != 0) { System.arraycopy(this.blockData, this.blockDataPosition, data, offset, remain); offset += remain; length -= remain; } readNextBlock (); } System.arraycopy(this.blockData, this.blockDataPosition, data, offset, length); this.blockDataPosition += length;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -