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 + -
显示快捷键?