📄 objectstreamclassutil_1_3.java
字号:
/* * @(#)ObjectStreamClassUtil_1_3.java 1.8 05/11/17 * * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */package com.sun.corba.se.impl.orbutil;// for computing the structural UIDimport java.security.MessageDigest;import java.security.NoSuchAlgorithmException;import java.security.DigestOutputStream;import java.security.AccessController;import java.security.PrivilegedExceptionAction;import java.security.PrivilegedActionException;import java.security.PrivilegedAction;import java.io.DataOutputStream;import java.io.ByteArrayOutputStream;import java.io.IOException;import java.util.Arrays;import java.util.Comparator;import java.lang.reflect.Field;import java.lang.reflect.Modifier;import java.lang.reflect.Array;import java.lang.reflect.Member;import java.lang.reflect.Method;import java.lang.reflect.Constructor;import com.sun.corba.se.impl.io.ObjectStreamClass;public final class ObjectStreamClassUtil_1_3 { // maintained here for backward compatability with JDK 1.3, where // writeObject method was not being checked at all, so there is // no need to lookup the ObjectStreamClass public static long computeSerialVersionUID(final Class cl) { long csuid = ObjectStreamClass.getSerialVersionUID(cl); if (csuid == 0) return csuid; // for non-serializable/proxy classes csuid = (ObjectStreamClassUtil_1_3.getSerialVersion(csuid, cl).longValue()); return csuid; } // to maintain same suid as the JDK 1.3, we pick // up suid only for classes with private,static,final // declarations, and compute it for all others private static Long getSerialVersion(final long csuid, final Class cl) { return (Long) AccessController.doPrivileged(new PrivilegedAction() { public Object run() { long suid; try { final Field f = cl.getDeclaredField("serialVersionUID"); int mods = f.getModifiers(); if (Modifier.isStatic(mods) && Modifier.isFinal(mods) && Modifier.isPrivate(mods)) { suid = csuid; } else { suid = _computeSerialVersionUID(cl); } } catch (NoSuchFieldException ex) { suid = _computeSerialVersionUID(cl); //} catch (IllegalAccessException ex) { // suid = _computeSerialVersionUID(cl); } return new Long(suid); } }); } public static long computeStructuralUID(boolean hasWriteObject, 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); //In the old case, for the caller class, the write Method wasn't considered // for rep-id calculations correctly, but for parent classes it was taken // into account. That is the reason there is the klude of getting the write // Object method in there // Get SUID of parent Class parent = cl.getSuperclass(); if ((parent != null) && (parent != java.lang.Object.class)) { boolean hasWriteObjectFlag = false; Class [] args = {java.io.ObjectOutputStream.class}; Method hasWriteObjectMethod = ObjectStreamClassUtil_1_3.getDeclaredMethod(parent, "writeObject", args, Modifier.PRIVATE, Modifier.STATIC); if (hasWriteObjectMethod != null) hasWriteObjectFlag = true; data.writeLong(ObjectStreamClassUtil_1_3.computeStructuralUID(hasWriteObjectFlag, parent)); } if (hasWriteObject) data.writeInt(2); else data.writeInt(1); /* Sort the field names to get a deterministic order */ Field[] field = ObjectStreamClassUtil_1_3.getDeclaredFields(cl); 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 * transient or static. */ int m = f.getModifiers(); if (Modifier.isTransient(m) || Modifier.isStatic(m)) continue; data.writeUTF(f.getName()); data.writeUTF(getSignature(f.getType())); } /* 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); for (int i = minimum; i > 0; 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 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())); } // need to find the java replacement for hasStaticInitializer 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();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -