objectstreamclass.java

来自「JAVA 所有包」· Java 代码 · 共 1,822 行 · 第 1/4 页

JAVA
1,822
字号
		} else {		    // For each declared persistent field, look for an actual		    // reflected Field. If there is one, make sure it's the correct		    // type and cache it in the ObjectStreamClass for that field.		    for (int j = fields.length-1; j >= 0; j--) {			try {                            Field reflField = cl.getDeclaredField(fields[j].getName());			    if (fields[j].getType() == reflField.getType()) {				reflField.setAccessible(true);				fields[j].setField(reflField);			    }			} catch (NoSuchFieldException e) {			    // Nothing to do			}		    }		}	        return null;	    }	    });	    if (fields.length > 1)		Arrays.sort(fields);	    /* Set up field data for use while writing using the API api. */	    computeFieldInfo();	}        /* Get the serialVersionUID from the class.         * It uses the access override mechanism so make sure         * the field objects is only used here.         *         * NonSerializable classes have a serialVerisonUID of 0L.         */         if (isNonSerializable()) {             suid = 0L;         } else {             // Lookup special Serializable members using reflection.             AccessController.doPrivileged(new PrivilegedAction() {                public Object run() {                if (forProxyClass) {                    // proxy classes always have serialVersionUID of 0L                    suid = 0L;                } else {	            try {                        final Field f = cl.getDeclaredField("serialVersionUID");	                int mods = f.getModifiers();			// SerialBug 5:  static final SUID should be read	                if (Modifier.isStatic(mods) && Modifier.isFinal(mods) ) {                            f.setAccessible(true);		            suid = f.getLong(cl);			    // SerialBug 2: should be computed after writeObject			    // actualSuid = computeStructuralUID(cl);	                } else {		            suid = _computeSerialVersionUID(cl);	                    // SerialBug 2: should be computed after writeObject	                    // actualSuid = computeStructuralUID(cl);	                }	            } catch (NoSuchFieldException ex) {	                suid = _computeSerialVersionUID(cl);	                // SerialBug 2: should be computed after writeObject	                // actualSuid = computeStructuralUID(cl);                    } catch (IllegalAccessException ex) {                        suid = _computeSerialVersionUID(cl);                    }	        }                writeReplaceObjectMethod = ObjectStreamClass.getInheritableMethod(cl, 		    "writeReplace", noTypesList, Object.class);                readResolveObjectMethod = ObjectStreamClass.getInheritableMethod(cl, 		    "readResolve", noTypesList, Object.class);			if (externalizable) 		    cons = getExternalizableConstructor(cl) ;		else		    cons = getSerializableConstructor(cl) ;                if (serializable && !forProxyClass) {	            /* Look for the writeObject method	             * Set the accessible flag on it here. ObjectOutputStream	             * will call it as necessary.	             */		    writeObjectMethod = getPrivateMethod( cl, "writeObject",			new Class[] { java.io.ObjectOutputStream.class }, Void.TYPE ) ;		    readObjectMethod = getPrivateMethod( cl, "readObject",			new Class[] { java.io.ObjectInputStream.class }, Void.TYPE ) ;	        }	        return null;	    }	  });	}        // This call depends on a lot of information computed above!        actualSuid = ObjectStreamClass.computeStructuralUID(this, cl);        // If we have a write object method, precompute the        // RMI-IIOP stream format version 2 optional data        // repository ID.          if (hasWriteObject())            rmiiiopOptionalDataRepId = computeRMIIIOPOptionalDataRepId();        // This must be done last.        initialized = true;      }    }    /**     * Returns non-static private method with given signature defined by given     * class, or null if none found.  Access checks are disabled on the     * returned method (if any).     */    private static Method getPrivateMethod(Class cl, String name, 					   Class[] argTypes,					   Class returnType)    {	try {	    Method meth = cl.getDeclaredMethod(name, argTypes);	    meth.setAccessible(true);	    int mods = meth.getModifiers();	    return ((meth.getReturnType() == returnType) &&		    ((mods & Modifier.STATIC) == 0) &&		    ((mods & Modifier.PRIVATE) != 0)) ? meth : null;	} catch (NoSuchMethodException ex) {	    return null;	}    }    // Specific to RMI-IIOP    /**     * Java to IDL ptc-02-01-12 1.5.1     *     * "The rep_id string passed to the start_value method must be     * 'RMI:org.omg.custom.class:hashcode:suid' where class is the     * fully-qualified name of the class whose writeObject method     * is being invoked and hashcode and suid are the class's hashcode     * and SUID."     */    private String computeRMIIIOPOptionalDataRepId() {        StringBuffer sbuf = new StringBuffer("RMI:org.omg.custom.");        sbuf.append(RepositoryId.convertToISOLatin1(this.getName()));        sbuf.append(':');        sbuf.append(this.getActualSerialVersionUIDStr());        sbuf.append(':');        sbuf.append(this.getSerialVersionUIDStr());        return sbuf.toString();    }    /**     * This will return null if there is no writeObject method.     */    public final String getRMIIIOPOptionalDataRepId() {        return rmiiiopOptionalDataRepId;    }    /*     * Create an empty ObjectStreamClass for a class about to be read.     * This is separate from read so ObjectInputStream can assign the     * wire handle early, before any nested ObjectStreamClass might     * be read.     */    ObjectStreamClass(String n, long s) {	name = n;	suid = s;	superclass = null;    }    private static Object[] translateFields(Object objs[])        throws NoSuchFieldException {        try{            java.io.ObjectStreamField fields[] = (java.io.ObjectStreamField[])objs;            Object translation[] = null;                                   if (translatedFields == null)                translatedFields = new Hashtable();                                   translation = (Object[])translatedFields.get(fields);                                   if (translation != null)                return translation;            else {                Class osfClass = Class.forName("com.sun.corba.se.impl.io.ObjectStreamField");                translation = (Object[])java.lang.reflect.Array.newInstance(osfClass, objs.length);                Object arg[] = new Object[2];                Class types[] = {String.class, Class.class};                Constructor constructor = osfClass.getDeclaredConstructor(types);                for (int i = fields.length -1; i >= 0; i--){                    arg[0] = fields[i].getName();                    arg[1] = fields[i].getType();                                           translation[i] = constructor.newInstance(arg);                }                translatedFields.put(fields, translation);                                   }            return (Object[])translation;        }        catch(Throwable t){            NoSuchFieldException nsfe = new NoSuchFieldException();	    nsfe.initCause( t ) ;	    throw nsfe ;        }    }    /*     * Set the class this version descriptor matches.     * The base class name and serializable hash must match.     * Fill in the reflected Fields that will be used     * for reading.     */    final void setClass(Class cl) throws InvalidClassException {	if (cl == null) {	    localClassDesc = null;	    ofClass = null;	    computeFieldInfo();	    return;	}	localClassDesc = lookupInternal(cl);	if (localClassDesc == null)	    // XXX I18N, logging needed	    throw new InvalidClassException(cl.getName(),					    "Local class not compatible");	if (suid != localClassDesc.suid) {            /* Check for exceptional cases that allow mismatched suid. */            /* Allow adding Serializable or Externalizable             * to a later release of the class.             */            boolean addedSerialOrExtern =                isNonSerializable() || localClassDesc.isNonSerializable();	    /* Disregard the serialVersionUID of an array	     * when name and cl.Name differ. If resolveClass() returns	     * an array with a different package name,	     * the serialVersionUIDs will not match since the fully	     * qualified array class is used in the	     * computation of the array's serialVersionUID. There is	     * no way to set a permanent serialVersionUID for an array type.	     */            boolean arraySUID = (cl.isArray() && ! cl.getName().equals(name));            if (! arraySUID && ! addedSerialOrExtern ) {		// XXX I18N, logging needed		throw new InvalidClassException(cl.getName(),						"Local class not compatible:" +						" stream classdesc serialVersionUID=" + suid +						" local class serialVersionUID=" + localClassDesc.suid);	    }        }	/* compare the class names, stripping off package names. */	if (! compareClassNames(name, cl.getName(), '.'))	    // XXX I18N, logging needed            throw new InvalidClassException(cl.getName(),                         "Incompatible local class name. " +                         "Expected class name compatible with " +                         name);	/*	 * Test that both implement either serializable or externalizable.	 */	// The next check is more generic, since it covers the	// Proxy case, the JDK 1.3 serialization code has	// both checks        //if ((serializable && localClassDesc.externalizable) ||        //    (externalizable && localClassDesc.serializable))        //    throw new InvalidClassException(localCl.getName(),        //            "Serializable is incompatible with Externalizable");        if ((serializable != localClassDesc.serializable) ||            (externalizable != localClassDesc.externalizable) ||	    (!serializable && !externalizable))	    // XXX I18N, logging needed	    throw new InvalidClassException(cl.getName(),					    "Serialization incompatible with Externalization");	/* Set up the reflected Fields in the class where the value of each	 * field in this descriptor should be stored.	 * Each field in this ObjectStreamClass (the source) is located (by	 * name) in the ObjectStreamClass of the class(the destination).	 * In the usual (non-versioned case) the field is in both	 * descriptors and the types match, so the reflected Field is copied.	 * If the type does not match, a InvalidClass exception is thrown.	 * If the field is not present in the class, the reflected Field	 * remains null so the field will be read but discarded.	 * If extra fields are present in the class they are ignored. Their	 * values will be set to the default value by the object allocator.	 * Both the src and dest field list are sorted by type and name.	 */	ObjectStreamField[] destfield =	    (ObjectStreamField[])localClassDesc.fields;	ObjectStreamField[] srcfield =	    (ObjectStreamField[])fields;	int j = 0;    nextsrc:	for (int i = 0; i < srcfield.length; i++ ) {	    /* Find this field in the dest*/	    for (int k = j; k < destfield.length; k++) {		if (srcfield[i].getName().equals(destfield[k].getName())) {		    /* found match */		    if (srcfield[i].isPrimitive() &&			!srcfield[i].typeEquals(destfield[k])) {			// XXX I18N, logging needed			throw new InvalidClassException(cl.getName(),							"The type of field " +							srcfield[i].getName() +							" of class " + name +							" is incompatible.");		    }		    /* Skip over any fields in the dest that are not in the src */		    j = k;		    srcfield[i].setField(destfield[j].getField());		    // go on to the next source field		    continue nextsrc;		}	    }	}	/* Set up field data for use while reading from the input stream. */	computeFieldInfo();	/* Remember the class this represents */	ofClass = cl;        /* get the cache of these methods from the local class         * implementation.         */        readObjectMethod = localClassDesc.readObjectMethod;        readResolveObjectMethod = localClassDesc.readResolveObjectMethod;    }    /* Compare the base class names of streamName and localName.     *     * @return  Return true iff the base class name compare.     * @parameter streamName	Fully qualified class name.     * @parameter localName	Fully qualified class name.     * @parameter pkgSeparator	class names use either '.' or '/'.     *     * Only compare base class name to allow package renaming.     */    static boolean compareClassNames(String streamName,				     String localName,				     char pkgSeparator) {	/* compare the class names, stripping off package names. */	int streamNameIndex = streamName.lastIndexOf(pkgSeparator);	if (streamNameIndex < 0)	    streamNameIndex = 0;	int localNameIndex = localName.lastIndexOf(pkgSeparator);	if (localNameIndex < 0)	    localNameIndex = 0;	return streamName.regionMatches(false, streamNameIndex,					localName, localNameIndex,					streamName.length() - streamNameIndex);    }    /*     * Compare the types of two class descriptors.     * They match if they have the same class name and suid     */    final boolean typeEquals(ObjectStreamClass other) {	return (suid == other.suid) &&	    compareClassNames(name, other.name, '.');    }    /*     * Return the superclass descriptor of this descriptor.     */    final void setSuperclass(ObjectStreamClass s) {	superclass = s;    }    /*     * Return the superclass descriptor of this descriptor.     */    final ObjectStreamClass getSuperclass() {	return superclass;    }    /**     * Return whether the class has a readObject method     */    final boolean hasReadObject() {        return readObjectMethod != null;    }    /*     * Return whether the class has a writeObject method     */    final boolean hasWriteObject() {	return writeObjectMethod != null ;    }    /**     * Returns when or not this class should be custom     * marshaled (use chunking).  This should happen if     * it is Externalizable OR if it or     * any of its superclasses has a writeObject method,     */    final boolean isCustomMarshaled() {	return (hasWriteObject() || isExternalizable())            || (superclass != null && superclass.isCustomMarshaled());    }    /*     * Return true if all instances of 'this' Externalizable class     * are written in block-data mode from the stream that 'this' was read     * from. <p>     *     * In JDK 1.1, all Externalizable instances are not written     * in block-data mode.     * In JDK 1.2, all Externalizable instances, by default, are written     * in block-data mode and the Externalizable instance is terminated with     * tag TC_ENDBLOCKDATA. Change enabled the ability to skip Externalizable     * instances.     *     * IMPLEMENTATION NOTE:     *   This should have been a mode maintained per stream; however,     *   for compatibility reasons, it was only possible to record     *   this change per class. All Externalizable classes within     *   a given stream should either have this mode enabled or     *   disabled. This is enforced by not allowing the PROTOCOL_VERSION     *   of a stream to he changed after any objects have been written.     *     * @see ObjectOutputStream#useProtocolVersion     * @see ObjectStreamConstants#PROTOCOL_VERSION_1     * @see ObjectStreamConstants#PROTOCOL_VERSION_2     *     * @since JDK 1.2     */    boolean hasExternalizableBlockDataMode() {	return hasExternalizableBlockData;    }    /**     * Creates a new instance of the represented class.  If the class is     * externalizable, invokes its public no-arg constructor; otherwise, if the     * class is serializable, invokes the no-arg constructor of the first     * non-serializable superclass.  Throws UnsupportedOperationException if     * this class descriptor is not associated with a class, if the associated     * class is non-serializable or if the appropriate no-arg constructor is     * inaccessible/unavailable.     */

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?