📄 objectstreamclass.java
字号:
* * 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 writeObject method */ final boolean hasWriteObject() { return hasWriteObjectMethod; } final boolean isCustomMarshaled() { return (hasWriteObject() || isExternalizable()); } /* * 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 ObjectOuputStream#useProtocolVersion * @see ObjectStreamConstants#PROTOCOL_VERSION_1 * @see ObjectStreamConstants#PROTOCOL_VERSION_2 * * @since JDK 1.2 */ boolean hasExternalizableBlockDataMode() { return hasExternalizableBlockData; } /* * Return the ObjectStreamClass of the local class this one is based on. */ final ObjectStreamClass localClassDescriptor() { return localClassDesc; } /* * Get the Serializability of the class. */ boolean isSerializable() { return serializable; } /* * Get the externalizability of the class. */ boolean isExternalizable() { return externalizable; } boolean isNonSerializable() { return ! (externalizable || serializable); } /* * Calculate the size of the array needed to store primitive data and the * number of object references to read when reading from the input * stream. */ private void computeFieldInfo() { primBytes = 0; objFields = 0; for (int i = 0; i < fields.length; i++ ) { switch (fields[i].getTypeCode()) { case 'B': case 'Z': primBytes += 1; break; case 'C': case 'S': primBytes += 2; break; case 'I': case 'F': primBytes += 4; break; case 'J': case 'D' : primBytes += 8; break; case 'L': case '[': objFields += 1; break; } } } /* * Compute a hash for the specified class. Incrementally add * items to the hash accumulating in the digest stream. * Fold the hash into a long. Use the SHA secure hash function. */ private static long _computeSerialVersionUID(Class cl) { ByteArrayOutputStream devnull = new ByteArrayOutputStream(512); long h = 0; try { MessageDigest md = MessageDigest.getInstance("SHA"); DigestOutputStream mdo = new DigestOutputStream(devnull, md); DataOutputStream data = new DataOutputStream(mdo); data.writeUTF(cl.getName()); int classaccess = cl.getModifiers(); classaccess &= (Modifier.PUBLIC | Modifier.FINAL | Modifier.INTERFACE | Modifier.ABSTRACT); /* Workaround for javac bug that only set ABSTRACT for * interfaces if the interface had some methods. * The ABSTRACT bit reflects that the number of methods > 0. * This is required so correct hashes can be computed * for existing class files. * Previously this hack was previously present in the VM. */ Method[] method = cl.getDeclaredMethods(); if ((classaccess & Modifier.INTERFACE) != 0) { classaccess &= (~Modifier.ABSTRACT); if (method.length > 0) { classaccess |= Modifier.ABSTRACT; } } data.writeInt(classaccess); /* * Get the list of interfaces supported, * Accumulate their names their names in Lexical order * and add them to the hash */ if (!cl.isArray()) { /* In 1.2fcs, getInterfaces() was modified to return * {java.lang.Cloneable, java.io.Serializable} when * called on array classes. These values would upset * the computation of the hash, so we explicitly omit * them from its computation. */ Class interfaces[] = cl.getInterfaces(); Arrays.sort(interfaces, compareClassByName); for (int i = 0; i < interfaces.length; i++) { data.writeUTF(interfaces[i].getName()); } } /* Sort the field names to get a deterministic order */ Field[] field = cl.getDeclaredFields(); Arrays.sort(field, compareMemberByName); for (int i = 0; i < field.length; i++) { Field f = field[i]; /* Include in the hash all fields except those that are * private transient and private static. */ int m = f.getModifiers(); if (Modifier.isPrivate(m) && (Modifier.isTransient(m) || Modifier.isStatic(m))) continue; data.writeUTF(f.getName()); data.writeInt(m); data.writeUTF(getSignature(f.getType())); } if (hasStaticInitializer(cl)) { data.writeUTF("<clinit>"); data.writeInt(Modifier.STATIC); // TBD: what modifiers does it have data.writeUTF("()V"); } /* * Get the list of constructors including name and signature * Sort lexically, add all except the private constructors * to the hash with their access flags */ MethodSignature[] constructors = MethodSignature.removePrivateAndSort(cl.getDeclaredConstructors()); for (int i = 0; i < constructors.length; i++) { MethodSignature c = constructors[i]; String mname = "<init>"; String desc = c.signature; desc = desc.replace('/', '.'); data.writeUTF(mname); data.writeInt(c.member.getModifiers()); data.writeUTF(desc); } /* Include in the hash all methods except those that are * private transient and private static. */ MethodSignature[] methods = MethodSignature.removePrivateAndSort(method); for (int i = 0; i < methods.length; i++ ) { MethodSignature m = methods[i]; String desc = m.signature; desc = desc.replace('/', '.'); data.writeUTF(m.member.getName()); data.writeInt(m.member.getModifiers()); data.writeUTF(desc); } /* Compute the hash value for this class. * Use only the first 64 bits of the hash. */ data.flush(); byte hasharray[] = md.digest(); for (int i = 0; i < Math.min(8, hasharray.length); i++) { h += (long)(hasharray[i] & 255) << (i * 8); } } catch (IOException ignore) { /* can't happen, but be deterministic anyway. */ h = -1; } catch (NoSuchAlgorithmException complain) { throw new SecurityException(complain.getMessage()); } return h; } private static long computeStructuralUID(com.sun.corba.se.internal.io.ObjectStreamClass osc, Class cl) { ByteArrayOutputStream devnull = new ByteArrayOutputStream(512); long h = 0; try { if ((!java.io.Serializable.class.isAssignableFrom(cl)) || (cl.isInterface())){ return 0; } if (java.io.Externalizable.class.isAssignableFrom(cl)) { return 1; } MessageDigest md = MessageDigest.getInstance("SHA"); DigestOutputStream mdo = new DigestOutputStream(devnull, md); DataOutputStream data = new DataOutputStream(mdo); // Get SUID of parent Class parent = cl.getSuperclass(); if ((parent != null)) // SerialBug 1; acc. to spec the one for // java.lang.object // should be computed and put // && (parent != java.lang.Object.class)) { //data.writeLong(computeSerialVersionUID(null,parent)); data.writeLong(computeStructuralUID(lookup(parent), parent)); } if (osc.hasWriteObject()) data.writeInt(2); else data.writeInt(1); // CORBA formal 00-11-03 10.6.2: For each field of the // class that is mapped to IDL, sorted lexicographically // by Java field name, in increasing order... ObjectStreamField[] field = osc.getFields(); if (field.length > 1) { Arrays.sort(field, compareObjStrFieldsByName); } // ...Java field name in UTF encoding, field // descriptor, as defined by the JVM spec... for (int i = 0; i < field.length; i++) { data.writeUTF(field[i].getName()); data.writeUTF(field[i].getSignature()); } /* Compute the hash value for this class. * Use only the first 64 bits of the hash. */ data.flush(); byte hasharray[] = md.digest(); // int minimum = Math.min(8, hasharray.length); // SerialBug 3: SHA computation is wrong; for loop reversed //for (int i = minimum; i > 0; i--) for (int i = 0; i < Math.min(8, hasharray.length); i++) { h += (long)(hasharray[i] & 255) << (i * 8); } } catch (IOException ignore) { /* can't happen, but be deterministic anyway. */ h = -1; } catch (NoSuchAlgorithmException complain) { throw new SecurityException(complain.getMessage()); } return h; } /** * Compute the JVM signature for the class. */ static String getSignature(Class clazz) { String type = null; if (clazz.isArray()) { Class cl = clazz; int dimensions = 0; while (cl.isArray()) { dimensions++; cl = cl.getComponentType(); } StringBuffer sb = new StringBuffer(); for (int i = 0; i < dimensions; i++) { sb.append("["); } sb.append(getSignature(cl)); type = sb.toString(); } else if (clazz.isPrimitive()) { if (clazz == Integer.TYPE) { type = "I"; } else if (clazz == Byte.TYPE) { type = "B"; } else if (clazz == Long.TYPE) { type = "J"; } else if (clazz == Float.TYPE) { type = "F"; } else if (clazz == Double.TYPE) { type = "D"; } else if (clazz == Short.TYPE) { type = "S"; } else if (clazz == Character.TYPE) { type = "C"; } else if (clazz == Boolean.TYPE) { type = "Z"; } else if (clazz == Void.TYPE) { type = "V"; } } else { type = "L" + clazz.getName().replace('.', '/') + ";"; } return type; } /* * Compute the JVM method descriptor for the method. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -