emul/compact/src/main/java/java/io/ObjectStreamClass.java
brancharithmetic
changeset 755 5652acd48509
parent 601 5198affdb915
     1.1 --- a/emul/compact/src/main/java/java/io/ObjectStreamClass.java	Mon Jan 28 18:12:47 2013 +0100
     1.2 +++ b/emul/compact/src/main/java/java/io/ObjectStreamClass.java	Mon Feb 25 19:00:08 2013 +0100
     1.3 @@ -36,20 +36,12 @@
     1.4  import java.lang.reflect.Method;
     1.5  import java.lang.reflect.Modifier;
     1.6  import java.lang.reflect.Proxy;
     1.7 -import java.security.AccessController;
     1.8 -import java.security.MessageDigest;
     1.9 -import java.security.NoSuchAlgorithmException;
    1.10 -import java.security.PrivilegedAction;
    1.11  import java.util.ArrayList;
    1.12  import java.util.Arrays;
    1.13  import java.util.Collections;
    1.14  import java.util.Comparator;
    1.15  import java.util.HashSet;
    1.16  import java.util.Set;
    1.17 -import java.util.concurrent.ConcurrentHashMap;
    1.18 -import java.util.concurrent.ConcurrentMap;
    1.19 -import sun.misc.Unsafe;
    1.20 -import sun.reflect.ReflectionFactory;
    1.21  
    1.22  /**
    1.23   * Serialization's descriptor for classes.  It contains the name and
    1.24 @@ -76,27 +68,6 @@
    1.25      private static final ObjectStreamField[] serialPersistentFields =
    1.26          NO_FIELDS;
    1.27  
    1.28 -    /** reflection factory for obtaining serialization constructors */
    1.29 -    private static final ReflectionFactory reflFactory =
    1.30 -        AccessController.doPrivileged(
    1.31 -            new ReflectionFactory.GetReflectionFactoryAction());
    1.32 -
    1.33 -    private static class Caches {
    1.34 -        /** cache mapping local classes -> descriptors */
    1.35 -        static final ConcurrentMap<WeakClassKey,Reference<?>> localDescs =
    1.36 -            new ConcurrentHashMap<>();
    1.37 -
    1.38 -        /** cache mapping field group/local desc pairs -> field reflectors */
    1.39 -        static final ConcurrentMap<FieldReflectorKey,Reference<?>> reflectors =
    1.40 -            new ConcurrentHashMap<>();
    1.41 -
    1.42 -        /** queue for WeakReferences to local classes */
    1.43 -        private static final ReferenceQueue<Class<?>> localDescsQueue =
    1.44 -            new ReferenceQueue<>();
    1.45 -        /** queue for WeakReferences to field reflectors keys */
    1.46 -        private static final ReferenceQueue<Class<?>> reflectorsQueue =
    1.47 -            new ReferenceQueue<>();
    1.48 -    }
    1.49  
    1.50      /** class associated with this descriptor (if any) */
    1.51      private Class<?> cl;
    1.52 @@ -139,7 +110,7 @@
    1.53      /** number of non-primitive fields */
    1.54      private int numObjFields;
    1.55      /** reflector for setting/getting serializable field values */
    1.56 -    private FieldReflector fieldRefl;
    1.57 +//    private FieldReflector fieldRefl;
    1.58      /** data layout of serialized objects described by this class desc */
    1.59      private volatile ClassDataSlot[] dataLayout;
    1.60  
    1.61 @@ -216,13 +187,7 @@
    1.62      public long getSerialVersionUID() {
    1.63          // REMIND: synchronize instead of relying on volatile?
    1.64          if (suid == null) {
    1.65 -            suid = AccessController.doPrivileged(
    1.66 -                new PrivilegedAction<Long>() {
    1.67 -                    public Long run() {
    1.68 -                        return computeDefaultSUID(cl);
    1.69 -                    }
    1.70 -                }
    1.71 -            );
    1.72 +            return computeDefaultSUID(cl);
    1.73          }
    1.74          return suid.longValue();
    1.75      }
    1.76 @@ -280,26 +245,11 @@
    1.77          if (!(all || Serializable.class.isAssignableFrom(cl))) {
    1.78              return null;
    1.79          }
    1.80 -        processQueue(Caches.localDescsQueue, Caches.localDescs);
    1.81 -        WeakClassKey key = new WeakClassKey(cl, Caches.localDescsQueue);
    1.82 -        Reference<?> ref = Caches.localDescs.get(key);
    1.83          Object entry = null;
    1.84 -        if (ref != null) {
    1.85 -            entry = ref.get();
    1.86 -        }
    1.87          EntryFuture future = null;
    1.88          if (entry == null) {
    1.89              EntryFuture newEntry = new EntryFuture();
    1.90              Reference<?> newRef = new SoftReference<>(newEntry);
    1.91 -            do {
    1.92 -                if (ref != null) {
    1.93 -                    Caches.localDescs.remove(key, ref);
    1.94 -                }
    1.95 -                ref = Caches.localDescs.putIfAbsent(key, newRef);
    1.96 -                if (ref != null) {
    1.97 -                    entry = ref.get();
    1.98 -                }
    1.99 -            } while (ref != null && entry == null);
   1.100              if (entry == null) {
   1.101                  future = newEntry;
   1.102              }
   1.103 @@ -310,7 +260,7 @@
   1.104          }
   1.105          if (entry instanceof EntryFuture) {
   1.106              future = (EntryFuture) entry;
   1.107 -            if (future.getOwner() == Thread.currentThread()) {
   1.108 +            if (true) {
   1.109                  /*
   1.110                   * Handle nested call situation described by 4803747: waiting
   1.111                   * for future value to be set by a lookup() call further up the
   1.112 @@ -328,12 +278,8 @@
   1.113              } catch (Throwable th) {
   1.114                  entry = th;
   1.115              }
   1.116 -            if (future.set(entry)) {
   1.117 -                Caches.localDescs.put(key, new SoftReference<Object>(entry));
   1.118 -            } else {
   1.119 -                // nested lookup call already set future
   1.120 -                entry = future.get();
   1.121 -            }
   1.122 +            // nested lookup call already set future
   1.123 +            entry = future.get();
   1.124          }
   1.125  
   1.126          if (entry instanceof ObjectStreamClass) {
   1.127 @@ -358,7 +304,6 @@
   1.128      private static class EntryFuture {
   1.129  
   1.130          private static final Object unset = new Object();
   1.131 -        private final Thread owner = Thread.currentThread();
   1.132          private Object entry = unset;
   1.133  
   1.134          /**
   1.135 @@ -390,25 +335,8 @@
   1.136                      interrupted = true;
   1.137                  }
   1.138              }
   1.139 -            if (interrupted) {
   1.140 -                AccessController.doPrivileged(
   1.141 -                    new PrivilegedAction<Void>() {
   1.142 -                        public Void run() {
   1.143 -                            Thread.currentThread().interrupt();
   1.144 -                            return null;
   1.145 -                        }
   1.146 -                    }
   1.147 -                );
   1.148 -            }
   1.149              return entry;
   1.150          }
   1.151 -
   1.152 -        /**
   1.153 -         * Returns the thread that created this EntryFuture.
   1.154 -         */
   1.155 -        Thread getOwner() {
   1.156 -            return owner;
   1.157 -        }
   1.158      }
   1.159  
   1.160      /**
   1.161 @@ -426,60 +354,9 @@
   1.162          superDesc = (superCl != null) ? lookup(superCl, false) : null;
   1.163          localDesc = this;
   1.164  
   1.165 -        if (serializable) {
   1.166 -            AccessController.doPrivileged(new PrivilegedAction<Void>() {
   1.167 -                public Void run() {
   1.168 -                    if (isEnum) {
   1.169 -                        suid = Long.valueOf(0);
   1.170 -                        fields = NO_FIELDS;
   1.171 -                        return null;
   1.172 -                    }
   1.173 -                    if (cl.isArray()) {
   1.174 -                        fields = NO_FIELDS;
   1.175 -                        return null;
   1.176 -                    }
   1.177 +        suid = Long.valueOf(0);
   1.178 +        fields = NO_FIELDS;
   1.179  
   1.180 -                    suid = getDeclaredSUID(cl);
   1.181 -                    try {
   1.182 -                        fields = getSerialFields(cl);
   1.183 -                        computeFieldOffsets();
   1.184 -                    } catch (InvalidClassException e) {
   1.185 -                        serializeEx = deserializeEx = e;
   1.186 -                        fields = NO_FIELDS;
   1.187 -                    }
   1.188 -
   1.189 -                    if (externalizable) {
   1.190 -                        cons = getExternalizableConstructor(cl);
   1.191 -                    } else {
   1.192 -                        cons = getSerializableConstructor(cl);
   1.193 -                        writeObjectMethod = getPrivateMethod(cl, "writeObject",
   1.194 -                            new Class<?>[] { ObjectOutputStream.class },
   1.195 -                            Void.TYPE);
   1.196 -                        readObjectMethod = getPrivateMethod(cl, "readObject",
   1.197 -                            new Class<?>[] { ObjectInputStream.class },
   1.198 -                            Void.TYPE);
   1.199 -                        readObjectNoDataMethod = getPrivateMethod(
   1.200 -                            cl, "readObjectNoData", null, Void.TYPE);
   1.201 -                        hasWriteObjectData = (writeObjectMethod != null);
   1.202 -                    }
   1.203 -                    writeReplaceMethod = getInheritableMethod(
   1.204 -                        cl, "writeReplace", null, Object.class);
   1.205 -                    readResolveMethod = getInheritableMethod(
   1.206 -                        cl, "readResolve", null, Object.class);
   1.207 -                    return null;
   1.208 -                }
   1.209 -            });
   1.210 -        } else {
   1.211 -            suid = Long.valueOf(0);
   1.212 -            fields = NO_FIELDS;
   1.213 -        }
   1.214 -
   1.215 -        try {
   1.216 -            fieldRefl = getReflector(fields, this);
   1.217 -        } catch (InvalidClassException ex) {
   1.218 -            // field mismatches impossible when matching local fields vs. self
   1.219 -            throw new InternalError();
   1.220 -        }
   1.221  
   1.222          if (deserializeEx == null) {
   1.223              if (isEnum) {
   1.224 @@ -533,7 +410,6 @@
   1.225              readResolveMethod = localDesc.readResolveMethod;
   1.226              deserializeEx = localDesc.deserializeEx;
   1.227          }
   1.228 -        fieldRefl = getReflector(fields, localDesc);
   1.229      }
   1.230  
   1.231      /**
   1.232 @@ -616,9 +492,8 @@
   1.233                  deserializeEx = localDesc.deserializeEx;
   1.234              }
   1.235          }
   1.236 -        fieldRefl = getReflector(fields, localDesc);
   1.237          // reassign to matched fields so as to reflect local unshared settings
   1.238 -        fields = fieldRefl.getFields();
   1.239 +        fields = null;
   1.240      }
   1.241  
   1.242      /**
   1.243 @@ -1197,7 +1072,6 @@
   1.244       * non-null.
   1.245       */
   1.246      void getPrimFieldValues(Object obj, byte[] buf) {
   1.247 -        fieldRefl.getPrimFieldValues(obj, buf);
   1.248      }
   1.249  
   1.250      /**
   1.251 @@ -1207,7 +1081,6 @@
   1.252       * non-null.
   1.253       */
   1.254      void setPrimFieldValues(Object obj, byte[] buf) {
   1.255 -        fieldRefl.setPrimFieldValues(obj, buf);
   1.256      }
   1.257  
   1.258      /**
   1.259 @@ -1216,7 +1089,6 @@
   1.260       * the caller to ensure that obj is of the proper type if non-null.
   1.261       */
   1.262      void getObjFieldValues(Object obj, Object[] vals) {
   1.263 -        fieldRefl.getObjFieldValues(obj, vals);
   1.264      }
   1.265  
   1.266      /**
   1.267 @@ -1225,7 +1097,6 @@
   1.268       * to ensure that obj is of the proper type if non-null.
   1.269       */
   1.270      void setObjFieldValues(Object obj, Object[] vals) {
   1.271 -        fieldRefl.setObjFieldValues(obj, vals);
   1.272      }
   1.273  
   1.274      /**
   1.275 @@ -1309,14 +1180,7 @@
   1.276       * the defining class may still be non-public.
   1.277       */
   1.278      private static Constructor getExternalizableConstructor(Class<?> cl) {
   1.279 -        try {
   1.280 -            Constructor cons = cl.getDeclaredConstructor((Class<?>[]) null);
   1.281 -            cons.setAccessible(true);
   1.282 -            return ((cons.getModifiers() & Modifier.PUBLIC) != 0) ?
   1.283 -                cons : null;
   1.284 -        } catch (NoSuchMethodException ex) {
   1.285 -            return null;
   1.286 -        }
   1.287 +        throw new SecurityException();
   1.288      }
   1.289  
   1.290      /**
   1.291 @@ -1331,21 +1195,7 @@
   1.292                  return null;
   1.293              }
   1.294          }
   1.295 -        try {
   1.296 -            Constructor cons = initCl.getDeclaredConstructor((Class<?>[]) null);
   1.297 -            int mods = cons.getModifiers();
   1.298 -            if ((mods & Modifier.PRIVATE) != 0 ||
   1.299 -                ((mods & (Modifier.PUBLIC | Modifier.PROTECTED)) == 0 &&
   1.300 -                 !packageEquals(cl, initCl)))
   1.301 -            {
   1.302 -                return null;
   1.303 -            }
   1.304 -            cons = reflFactory.newConstructorForSerialization(cl, cons);
   1.305 -            cons.setAccessible(true);
   1.306 -            return cons;
   1.307 -        } catch (NoSuchMethodException ex) {
   1.308 -            return null;
   1.309 -        }
   1.310 +        throw new SecurityException();
   1.311      }
   1.312  
   1.313      /**
   1.314 @@ -1358,31 +1208,7 @@
   1.315                                                 Class<?>[] argTypes,
   1.316                                                 Class<?> returnType)
   1.317      {
   1.318 -        Method meth = null;
   1.319 -        Class<?> defCl = cl;
   1.320 -        while (defCl != null) {
   1.321 -            try {
   1.322 -                meth = defCl.getDeclaredMethod(name, argTypes);
   1.323 -                break;
   1.324 -            } catch (NoSuchMethodException ex) {
   1.325 -                defCl = defCl.getSuperclass();
   1.326 -            }
   1.327 -        }
   1.328 -
   1.329 -        if ((meth == null) || (meth.getReturnType() != returnType)) {
   1.330 -            return null;
   1.331 -        }
   1.332 -        meth.setAccessible(true);
   1.333 -        int mods = meth.getModifiers();
   1.334 -        if ((mods & (Modifier.STATIC | Modifier.ABSTRACT)) != 0) {
   1.335 -            return null;
   1.336 -        } else if ((mods & (Modifier.PUBLIC | Modifier.PROTECTED)) != 0) {
   1.337 -            return meth;
   1.338 -        } else if ((mods & Modifier.PRIVATE) != 0) {
   1.339 -            return (cl == defCl) ? meth : null;
   1.340 -        } else {
   1.341 -            return packageEquals(cl, defCl) ? meth : null;
   1.342 -        }
   1.343 +        throw new SecurityException();
   1.344      }
   1.345  
   1.346      /**
   1.347 @@ -1394,16 +1220,7 @@
   1.348                                             Class<?>[] argTypes,
   1.349                                             Class<?> returnType)
   1.350      {
   1.351 -        try {
   1.352 -            Method meth = cl.getDeclaredMethod(name, argTypes);
   1.353 -            meth.setAccessible(true);
   1.354 -            int mods = meth.getModifiers();
   1.355 -            return ((meth.getReturnType() == returnType) &&
   1.356 -                    ((mods & Modifier.STATIC) == 0) &&
   1.357 -                    ((mods & Modifier.PRIVATE) != 0)) ? meth : null;
   1.358 -        } catch (NoSuchMethodException ex) {
   1.359 -            return null;
   1.360 -        }
   1.361 +        throw new SecurityException();
   1.362      }
   1.363  
   1.364      /**
   1.365 @@ -1548,52 +1365,7 @@
   1.366      private static ObjectStreamField[] getDeclaredSerialFields(Class<?> cl)
   1.367          throws InvalidClassException
   1.368      {
   1.369 -        ObjectStreamField[] serialPersistentFields = null;
   1.370 -        try {
   1.371 -            Field f = cl.getDeclaredField("serialPersistentFields");
   1.372 -            int mask = Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL;
   1.373 -            if ((f.getModifiers() & mask) == mask) {
   1.374 -                f.setAccessible(true);
   1.375 -                serialPersistentFields = (ObjectStreamField[]) f.get(null);
   1.376 -            }
   1.377 -        } catch (Exception ex) {
   1.378 -        }
   1.379 -        if (serialPersistentFields == null) {
   1.380 -            return null;
   1.381 -        } else if (serialPersistentFields.length == 0) {
   1.382 -            return NO_FIELDS;
   1.383 -        }
   1.384 -
   1.385 -        ObjectStreamField[] boundFields =
   1.386 -            new ObjectStreamField[serialPersistentFields.length];
   1.387 -        Set<String> fieldNames = new HashSet<>(serialPersistentFields.length);
   1.388 -
   1.389 -        for (int i = 0; i < serialPersistentFields.length; i++) {
   1.390 -            ObjectStreamField spf = serialPersistentFields[i];
   1.391 -
   1.392 -            String fname = spf.getName();
   1.393 -            if (fieldNames.contains(fname)) {
   1.394 -                throw new InvalidClassException(
   1.395 -                    "multiple serializable fields named " + fname);
   1.396 -            }
   1.397 -            fieldNames.add(fname);
   1.398 -
   1.399 -            try {
   1.400 -                Field f = cl.getDeclaredField(fname);
   1.401 -                if ((f.getType() == spf.getType()) &&
   1.402 -                    ((f.getModifiers() & Modifier.STATIC) == 0))
   1.403 -                {
   1.404 -                    boundFields[i] =
   1.405 -                        new ObjectStreamField(f, spf.isUnshared(), true);
   1.406 -                }
   1.407 -            } catch (NoSuchFieldException ex) {
   1.408 -            }
   1.409 -            if (boundFields[i] == null) {
   1.410 -                boundFields[i] = new ObjectStreamField(
   1.411 -                    fname, spf.getType(), spf.isUnshared());
   1.412 -            }
   1.413 -        }
   1.414 -        return boundFields;
   1.415 +        throw new SecurityException();
   1.416      }
   1.417  
   1.418      /**
   1.419 @@ -1603,18 +1375,7 @@
   1.420       * serializable fields exist, NO_FIELDS is returned.
   1.421       */
   1.422      private static ObjectStreamField[] getDefaultSerialFields(Class<?> cl) {
   1.423 -        Field[] clFields = cl.getDeclaredFields();
   1.424 -        ArrayList<ObjectStreamField> list = new ArrayList<>();
   1.425 -        int mask = Modifier.STATIC | Modifier.TRANSIENT;
   1.426 -
   1.427 -        for (int i = 0; i < clFields.length; i++) {
   1.428 -            if ((clFields[i].getModifiers() & mask) == 0) {
   1.429 -                list.add(new ObjectStreamField(clFields[i], false, true));
   1.430 -            }
   1.431 -        }
   1.432 -        int size = list.size();
   1.433 -        return (size == 0) ? NO_FIELDS :
   1.434 -            list.toArray(new ObjectStreamField[size]);
   1.435 +        throw new SecurityException();
   1.436      }
   1.437  
   1.438      /**
   1.439 @@ -1622,15 +1383,6 @@
   1.440       * null if none.
   1.441       */
   1.442      private static Long getDeclaredSUID(Class<?> cl) {
   1.443 -        try {
   1.444 -            Field f = cl.getDeclaredField("serialVersionUID");
   1.445 -            int mask = Modifier.STATIC | Modifier.FINAL;
   1.446 -            if ((f.getModifiers() & mask) == mask) {
   1.447 -                f.setAccessible(true);
   1.448 -                return Long.valueOf(f.getLong(null));
   1.449 -            }
   1.450 -        } catch (Exception ex) {
   1.451 -        }
   1.452          return null;
   1.453      }
   1.454  
   1.455 @@ -1638,667 +1390,7 @@
   1.456       * Computes the default serial version UID value for the given class.
   1.457       */
   1.458      private static long computeDefaultSUID(Class<?> cl) {
   1.459 -        if (!Serializable.class.isAssignableFrom(cl) || Proxy.isProxyClass(cl))
   1.460 -        {
   1.461 -            return 0L;
   1.462 -        }
   1.463 -
   1.464 -        try {
   1.465 -            ByteArrayOutputStream bout = new ByteArrayOutputStream();
   1.466 -            DataOutputStream dout = new DataOutputStream(bout);
   1.467 -
   1.468 -            dout.writeUTF(cl.getName());
   1.469 -
   1.470 -            int classMods = cl.getModifiers() &
   1.471 -                (Modifier.PUBLIC | Modifier.FINAL |
   1.472 -                 Modifier.INTERFACE | Modifier.ABSTRACT);
   1.473 -
   1.474 -            /*
   1.475 -             * compensate for javac bug in which ABSTRACT bit was set for an
   1.476 -             * interface only if the interface declared methods
   1.477 -             */
   1.478 -            Method[] methods = cl.getDeclaredMethods();
   1.479 -            if ((classMods & Modifier.INTERFACE) != 0) {
   1.480 -                classMods = (methods.length > 0) ?
   1.481 -                    (classMods | Modifier.ABSTRACT) :
   1.482 -                    (classMods & ~Modifier.ABSTRACT);
   1.483 -            }
   1.484 -            dout.writeInt(classMods);
   1.485 -
   1.486 -            if (!cl.isArray()) {
   1.487 -                /*
   1.488 -                 * compensate for change in 1.2FCS in which
   1.489 -                 * Class.getInterfaces() was modified to return Cloneable and
   1.490 -                 * Serializable for array classes.
   1.491 -                 */
   1.492 -                Class<?>[] interfaces = cl.getInterfaces();
   1.493 -                String[] ifaceNames = new String[interfaces.length];
   1.494 -                for (int i = 0; i < interfaces.length; i++) {
   1.495 -                    ifaceNames[i] = interfaces[i].getName();
   1.496 -                }
   1.497 -                Arrays.sort(ifaceNames);
   1.498 -                for (int i = 0; i < ifaceNames.length; i++) {
   1.499 -                    dout.writeUTF(ifaceNames[i]);
   1.500 -                }
   1.501 -            }
   1.502 -
   1.503 -            Field[] fields = cl.getDeclaredFields();
   1.504 -            MemberSignature[] fieldSigs = new MemberSignature[fields.length];
   1.505 -            for (int i = 0; i < fields.length; i++) {
   1.506 -                fieldSigs[i] = new MemberSignature(fields[i]);
   1.507 -            }
   1.508 -            Arrays.sort(fieldSigs, new Comparator<MemberSignature>() {
   1.509 -                public int compare(MemberSignature ms1, MemberSignature ms2) {
   1.510 -                    return ms1.name.compareTo(ms2.name);
   1.511 -                }
   1.512 -            });
   1.513 -            for (int i = 0; i < fieldSigs.length; i++) {
   1.514 -                MemberSignature sig = fieldSigs[i];
   1.515 -                int mods = sig.member.getModifiers() &
   1.516 -                    (Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED |
   1.517 -                     Modifier.STATIC | Modifier.FINAL | Modifier.VOLATILE |
   1.518 -                     Modifier.TRANSIENT);
   1.519 -                if (((mods & Modifier.PRIVATE) == 0) ||
   1.520 -                    ((mods & (Modifier.STATIC | Modifier.TRANSIENT)) == 0))
   1.521 -                {
   1.522 -                    dout.writeUTF(sig.name);
   1.523 -                    dout.writeInt(mods);
   1.524 -                    dout.writeUTF(sig.signature);
   1.525 -                }
   1.526 -            }
   1.527 -
   1.528 -            if (hasStaticInitializer(cl)) {
   1.529 -                dout.writeUTF("<clinit>");
   1.530 -                dout.writeInt(Modifier.STATIC);
   1.531 -                dout.writeUTF("()V");
   1.532 -            }
   1.533 -
   1.534 -            Constructor[] cons = cl.getDeclaredConstructors();
   1.535 -            MemberSignature[] consSigs = new MemberSignature[cons.length];
   1.536 -            for (int i = 0; i < cons.length; i++) {
   1.537 -                consSigs[i] = new MemberSignature(cons[i]);
   1.538 -            }
   1.539 -            Arrays.sort(consSigs, new Comparator<MemberSignature>() {
   1.540 -                public int compare(MemberSignature ms1, MemberSignature ms2) {
   1.541 -                    return ms1.signature.compareTo(ms2.signature);
   1.542 -                }
   1.543 -            });
   1.544 -            for (int i = 0; i < consSigs.length; i++) {
   1.545 -                MemberSignature sig = consSigs[i];
   1.546 -                int mods = sig.member.getModifiers() &
   1.547 -                    (Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED |
   1.548 -                     Modifier.STATIC | Modifier.FINAL |
   1.549 -                     Modifier.SYNCHRONIZED | Modifier.NATIVE |
   1.550 -                     Modifier.ABSTRACT | Modifier.STRICT);
   1.551 -                if ((mods & Modifier.PRIVATE) == 0) {
   1.552 -                    dout.writeUTF("<init>");
   1.553 -                    dout.writeInt(mods);
   1.554 -                    dout.writeUTF(sig.signature.replace('/', '.'));
   1.555 -                }
   1.556 -            }
   1.557 -
   1.558 -            MemberSignature[] methSigs = new MemberSignature[methods.length];
   1.559 -            for (int i = 0; i < methods.length; i++) {
   1.560 -                methSigs[i] = new MemberSignature(methods[i]);
   1.561 -            }
   1.562 -            Arrays.sort(methSigs, new Comparator<MemberSignature>() {
   1.563 -                public int compare(MemberSignature ms1, MemberSignature ms2) {
   1.564 -                    int comp = ms1.name.compareTo(ms2.name);
   1.565 -                    if (comp == 0) {
   1.566 -                        comp = ms1.signature.compareTo(ms2.signature);
   1.567 -                    }
   1.568 -                    return comp;
   1.569 -                }
   1.570 -            });
   1.571 -            for (int i = 0; i < methSigs.length; i++) {
   1.572 -                MemberSignature sig = methSigs[i];
   1.573 -                int mods = sig.member.getModifiers() &
   1.574 -                    (Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED |
   1.575 -                     Modifier.STATIC | Modifier.FINAL |
   1.576 -                     Modifier.SYNCHRONIZED | Modifier.NATIVE |
   1.577 -                     Modifier.ABSTRACT | Modifier.STRICT);
   1.578 -                if ((mods & Modifier.PRIVATE) == 0) {
   1.579 -                    dout.writeUTF(sig.name);
   1.580 -                    dout.writeInt(mods);
   1.581 -                    dout.writeUTF(sig.signature.replace('/', '.'));
   1.582 -                }
   1.583 -            }
   1.584 -
   1.585 -            dout.flush();
   1.586 -
   1.587 -            MessageDigest md = MessageDigest.getInstance("SHA");
   1.588 -            byte[] hashBytes = md.digest(bout.toByteArray());
   1.589 -            long hash = 0;
   1.590 -            for (int i = Math.min(hashBytes.length, 8) - 1; i >= 0; i--) {
   1.591 -                hash = (hash << 8) | (hashBytes[i] & 0xFF);
   1.592 -            }
   1.593 -            return hash;
   1.594 -        } catch (IOException ex) {
   1.595 -            throw new InternalError();
   1.596 -        } catch (NoSuchAlgorithmException ex) {
   1.597 -            throw new SecurityException(ex.getMessage());
   1.598 -        }
   1.599 +        throw new SecurityException();
   1.600      }
   1.601  
   1.602 -    /**
   1.603 -     * Returns true if the given class defines a static initializer method,
   1.604 -     * false otherwise.
   1.605 -     */
   1.606 -    private native static boolean hasStaticInitializer(Class<?> cl);
   1.607 -
   1.608 -    /**
   1.609 -     * Class for computing and caching field/constructor/method signatures
   1.610 -     * during serialVersionUID calculation.
   1.611 -     */
   1.612 -    private static class MemberSignature {
   1.613 -
   1.614 -        public final Member member;
   1.615 -        public final String name;
   1.616 -        public final String signature;
   1.617 -
   1.618 -        public MemberSignature(Field field) {
   1.619 -            member = field;
   1.620 -            name = field.getName();
   1.621 -            signature = getClassSignature(field.getType());
   1.622 -        }
   1.623 -
   1.624 -        public MemberSignature(Constructor cons) {
   1.625 -            member = cons;
   1.626 -            name = cons.getName();
   1.627 -            signature = getMethodSignature(
   1.628 -                cons.getParameterTypes(), Void.TYPE);
   1.629 -        }
   1.630 -
   1.631 -        public MemberSignature(Method meth) {
   1.632 -            member = meth;
   1.633 -            name = meth.getName();
   1.634 -            signature = getMethodSignature(
   1.635 -                meth.getParameterTypes(), meth.getReturnType());
   1.636 -        }
   1.637 -    }
   1.638 -
   1.639 -    /**
   1.640 -     * Class for setting and retrieving serializable field values in batch.
   1.641 -     */
   1.642 -    // REMIND: dynamically generate these?
   1.643 -    private static class FieldReflector {
   1.644 -
   1.645 -        /** handle for performing unsafe operations */
   1.646 -        private static final Unsafe unsafe = Unsafe.getUnsafe();
   1.647 -
   1.648 -        /** fields to operate on */
   1.649 -        private final ObjectStreamField[] fields;
   1.650 -        /** number of primitive fields */
   1.651 -        private final int numPrimFields;
   1.652 -        /** unsafe field keys for reading fields - may contain dupes */
   1.653 -        private final long[] readKeys;
   1.654 -        /** unsafe fields keys for writing fields - no dupes */
   1.655 -        private final long[] writeKeys;
   1.656 -        /** field data offsets */
   1.657 -        private final int[] offsets;
   1.658 -        /** field type codes */
   1.659 -        private final char[] typeCodes;
   1.660 -        /** field types */
   1.661 -        private final Class<?>[] types;
   1.662 -
   1.663 -        /**
   1.664 -         * Constructs FieldReflector capable of setting/getting values from the
   1.665 -         * subset of fields whose ObjectStreamFields contain non-null
   1.666 -         * reflective Field objects.  ObjectStreamFields with null Fields are
   1.667 -         * treated as filler, for which get operations return default values
   1.668 -         * and set operations discard given values.
   1.669 -         */
   1.670 -        FieldReflector(ObjectStreamField[] fields) {
   1.671 -            this.fields = fields;
   1.672 -            int nfields = fields.length;
   1.673 -            readKeys = new long[nfields];
   1.674 -            writeKeys = new long[nfields];
   1.675 -            offsets = new int[nfields];
   1.676 -            typeCodes = new char[nfields];
   1.677 -            ArrayList<Class<?>> typeList = new ArrayList<>();
   1.678 -            Set<Long> usedKeys = new HashSet<>();
   1.679 -
   1.680 -
   1.681 -            for (int i = 0; i < nfields; i++) {
   1.682 -                ObjectStreamField f = fields[i];
   1.683 -                Field rf = f.getField();
   1.684 -                long key = (rf != null) ?
   1.685 -                    unsafe.objectFieldOffset(rf) : Unsafe.INVALID_FIELD_OFFSET;
   1.686 -                readKeys[i] = key;
   1.687 -                writeKeys[i] = usedKeys.add(key) ?
   1.688 -                    key : Unsafe.INVALID_FIELD_OFFSET;
   1.689 -                offsets[i] = f.getOffset();
   1.690 -                typeCodes[i] = f.getTypeCode();
   1.691 -                if (!f.isPrimitive()) {
   1.692 -                    typeList.add((rf != null) ? rf.getType() : null);
   1.693 -                }
   1.694 -            }
   1.695 -
   1.696 -            types = typeList.toArray(new Class<?>[typeList.size()]);
   1.697 -            numPrimFields = nfields - types.length;
   1.698 -        }
   1.699 -
   1.700 -        /**
   1.701 -         * Returns list of ObjectStreamFields representing fields operated on
   1.702 -         * by this reflector.  The shared/unshared values and Field objects
   1.703 -         * contained by ObjectStreamFields in the list reflect their bindings
   1.704 -         * to locally defined serializable fields.
   1.705 -         */
   1.706 -        ObjectStreamField[] getFields() {
   1.707 -            return fields;
   1.708 -        }
   1.709 -
   1.710 -        /**
   1.711 -         * Fetches the serializable primitive field values of object obj and
   1.712 -         * marshals them into byte array buf starting at offset 0.  The caller
   1.713 -         * is responsible for ensuring that obj is of the proper type.
   1.714 -         */
   1.715 -        void getPrimFieldValues(Object obj, byte[] buf) {
   1.716 -            if (obj == null) {
   1.717 -                throw new NullPointerException();
   1.718 -            }
   1.719 -            /* assuming checkDefaultSerialize() has been called on the class
   1.720 -             * descriptor this FieldReflector was obtained from, no field keys
   1.721 -             * in array should be equal to Unsafe.INVALID_FIELD_OFFSET.
   1.722 -             */
   1.723 -            for (int i = 0; i < numPrimFields; i++) {
   1.724 -                long key = readKeys[i];
   1.725 -                int off = offsets[i];
   1.726 -                switch (typeCodes[i]) {
   1.727 -                    case 'Z':
   1.728 -                        Bits.putBoolean(buf, off, unsafe.getBoolean(obj, key));
   1.729 -                        break;
   1.730 -
   1.731 -                    case 'B':
   1.732 -                        buf[off] = unsafe.getByte(obj, key);
   1.733 -                        break;
   1.734 -
   1.735 -                    case 'C':
   1.736 -                        Bits.putChar(buf, off, unsafe.getChar(obj, key));
   1.737 -                        break;
   1.738 -
   1.739 -                    case 'S':
   1.740 -                        Bits.putShort(buf, off, unsafe.getShort(obj, key));
   1.741 -                        break;
   1.742 -
   1.743 -                    case 'I':
   1.744 -                        Bits.putInt(buf, off, unsafe.getInt(obj, key));
   1.745 -                        break;
   1.746 -
   1.747 -                    case 'F':
   1.748 -                        Bits.putFloat(buf, off, unsafe.getFloat(obj, key));
   1.749 -                        break;
   1.750 -
   1.751 -                    case 'J':
   1.752 -                        Bits.putLong(buf, off, unsafe.getLong(obj, key));
   1.753 -                        break;
   1.754 -
   1.755 -                    case 'D':
   1.756 -                        Bits.putDouble(buf, off, unsafe.getDouble(obj, key));
   1.757 -                        break;
   1.758 -
   1.759 -                    default:
   1.760 -                        throw new InternalError();
   1.761 -                }
   1.762 -            }
   1.763 -        }
   1.764 -
   1.765 -        /**
   1.766 -         * Sets the serializable primitive fields of object obj using values
   1.767 -         * unmarshalled from byte array buf starting at offset 0.  The caller
   1.768 -         * is responsible for ensuring that obj is of the proper type.
   1.769 -         */
   1.770 -        void setPrimFieldValues(Object obj, byte[] buf) {
   1.771 -            if (obj == null) {
   1.772 -                throw new NullPointerException();
   1.773 -            }
   1.774 -            for (int i = 0; i < numPrimFields; i++) {
   1.775 -                long key = writeKeys[i];
   1.776 -                if (key == Unsafe.INVALID_FIELD_OFFSET) {
   1.777 -                    continue;           // discard value
   1.778 -                }
   1.779 -                int off = offsets[i];
   1.780 -                switch (typeCodes[i]) {
   1.781 -                    case 'Z':
   1.782 -                        unsafe.putBoolean(obj, key, Bits.getBoolean(buf, off));
   1.783 -                        break;
   1.784 -
   1.785 -                    case 'B':
   1.786 -                        unsafe.putByte(obj, key, buf[off]);
   1.787 -                        break;
   1.788 -
   1.789 -                    case 'C':
   1.790 -                        unsafe.putChar(obj, key, Bits.getChar(buf, off));
   1.791 -                        break;
   1.792 -
   1.793 -                    case 'S':
   1.794 -                        unsafe.putShort(obj, key, Bits.getShort(buf, off));
   1.795 -                        break;
   1.796 -
   1.797 -                    case 'I':
   1.798 -                        unsafe.putInt(obj, key, Bits.getInt(buf, off));
   1.799 -                        break;
   1.800 -
   1.801 -                    case 'F':
   1.802 -                        unsafe.putFloat(obj, key, Bits.getFloat(buf, off));
   1.803 -                        break;
   1.804 -
   1.805 -                    case 'J':
   1.806 -                        unsafe.putLong(obj, key, Bits.getLong(buf, off));
   1.807 -                        break;
   1.808 -
   1.809 -                    case 'D':
   1.810 -                        unsafe.putDouble(obj, key, Bits.getDouble(buf, off));
   1.811 -                        break;
   1.812 -
   1.813 -                    default:
   1.814 -                        throw new InternalError();
   1.815 -                }
   1.816 -            }
   1.817 -        }
   1.818 -
   1.819 -        /**
   1.820 -         * Fetches the serializable object field values of object obj and
   1.821 -         * stores them in array vals starting at offset 0.  The caller is
   1.822 -         * responsible for ensuring that obj is of the proper type.
   1.823 -         */
   1.824 -        void getObjFieldValues(Object obj, Object[] vals) {
   1.825 -            if (obj == null) {
   1.826 -                throw new NullPointerException();
   1.827 -            }
   1.828 -            /* assuming checkDefaultSerialize() has been called on the class
   1.829 -             * descriptor this FieldReflector was obtained from, no field keys
   1.830 -             * in array should be equal to Unsafe.INVALID_FIELD_OFFSET.
   1.831 -             */
   1.832 -            for (int i = numPrimFields; i < fields.length; i++) {
   1.833 -                switch (typeCodes[i]) {
   1.834 -                    case 'L':
   1.835 -                    case '[':
   1.836 -                        vals[offsets[i]] = unsafe.getObject(obj, readKeys[i]);
   1.837 -                        break;
   1.838 -
   1.839 -                    default:
   1.840 -                        throw new InternalError();
   1.841 -                }
   1.842 -            }
   1.843 -        }
   1.844 -
   1.845 -        /**
   1.846 -         * Sets the serializable object fields of object obj using values from
   1.847 -         * array vals starting at offset 0.  The caller is responsible for
   1.848 -         * ensuring that obj is of the proper type; however, attempts to set a
   1.849 -         * field with a value of the wrong type will trigger an appropriate
   1.850 -         * ClassCastException.
   1.851 -         */
   1.852 -        void setObjFieldValues(Object obj, Object[] vals) {
   1.853 -            if (obj == null) {
   1.854 -                throw new NullPointerException();
   1.855 -            }
   1.856 -            for (int i = numPrimFields; i < fields.length; i++) {
   1.857 -                long key = writeKeys[i];
   1.858 -                if (key == Unsafe.INVALID_FIELD_OFFSET) {
   1.859 -                    continue;           // discard value
   1.860 -                }
   1.861 -                switch (typeCodes[i]) {
   1.862 -                    case 'L':
   1.863 -                    case '[':
   1.864 -                        Object val = vals[offsets[i]];
   1.865 -                        if (val != null &&
   1.866 -                            !types[i - numPrimFields].isInstance(val))
   1.867 -                        {
   1.868 -                            Field f = fields[i].getField();
   1.869 -                            throw new ClassCastException(
   1.870 -                                "cannot assign instance of " +
   1.871 -                                val.getClass().getName() + " to field " +
   1.872 -                                f.getDeclaringClass().getName() + "." +
   1.873 -                                f.getName() + " of type " +
   1.874 -                                f.getType().getName() + " in instance of " +
   1.875 -                                obj.getClass().getName());
   1.876 -                        }
   1.877 -                        unsafe.putObject(obj, key, val);
   1.878 -                        break;
   1.879 -
   1.880 -                    default:
   1.881 -                        throw new InternalError();
   1.882 -                }
   1.883 -            }
   1.884 -        }
   1.885 -    }
   1.886 -
   1.887 -    /**
   1.888 -     * Matches given set of serializable fields with serializable fields
   1.889 -     * described by the given local class descriptor, and returns a
   1.890 -     * FieldReflector instance capable of setting/getting values from the
   1.891 -     * subset of fields that match (non-matching fields are treated as filler,
   1.892 -     * for which get operations return default values and set operations
   1.893 -     * discard given values).  Throws InvalidClassException if unresolvable
   1.894 -     * type conflicts exist between the two sets of fields.
   1.895 -     */
   1.896 -    private static FieldReflector getReflector(ObjectStreamField[] fields,
   1.897 -                                               ObjectStreamClass localDesc)
   1.898 -        throws InvalidClassException
   1.899 -    {
   1.900 -        // class irrelevant if no fields
   1.901 -        Class<?> cl = (localDesc != null && fields.length > 0) ?
   1.902 -            localDesc.cl : null;
   1.903 -        processQueue(Caches.reflectorsQueue, Caches.reflectors);
   1.904 -        FieldReflectorKey key = new FieldReflectorKey(cl, fields,
   1.905 -                                                      Caches.reflectorsQueue);
   1.906 -        Reference<?> ref = Caches.reflectors.get(key);
   1.907 -        Object entry = null;
   1.908 -        if (ref != null) {
   1.909 -            entry = ref.get();
   1.910 -        }
   1.911 -        EntryFuture future = null;
   1.912 -        if (entry == null) {
   1.913 -            EntryFuture newEntry = new EntryFuture();
   1.914 -            Reference<?> newRef = new SoftReference<>(newEntry);
   1.915 -            do {
   1.916 -                if (ref != null) {
   1.917 -                    Caches.reflectors.remove(key, ref);
   1.918 -                }
   1.919 -                ref = Caches.reflectors.putIfAbsent(key, newRef);
   1.920 -                if (ref != null) {
   1.921 -                    entry = ref.get();
   1.922 -                }
   1.923 -            } while (ref != null && entry == null);
   1.924 -            if (entry == null) {
   1.925 -                future = newEntry;
   1.926 -            }
   1.927 -        }
   1.928 -
   1.929 -        if (entry instanceof FieldReflector) {  // check common case first
   1.930 -            return (FieldReflector) entry;
   1.931 -        } else if (entry instanceof EntryFuture) {
   1.932 -            entry = ((EntryFuture) entry).get();
   1.933 -        } else if (entry == null) {
   1.934 -            try {
   1.935 -                entry = new FieldReflector(matchFields(fields, localDesc));
   1.936 -            } catch (Throwable th) {
   1.937 -                entry = th;
   1.938 -            }
   1.939 -            future.set(entry);
   1.940 -            Caches.reflectors.put(key, new SoftReference<Object>(entry));
   1.941 -        }
   1.942 -
   1.943 -        if (entry instanceof FieldReflector) {
   1.944 -            return (FieldReflector) entry;
   1.945 -        } else if (entry instanceof InvalidClassException) {
   1.946 -            throw (InvalidClassException) entry;
   1.947 -        } else if (entry instanceof RuntimeException) {
   1.948 -            throw (RuntimeException) entry;
   1.949 -        } else if (entry instanceof Error) {
   1.950 -            throw (Error) entry;
   1.951 -        } else {
   1.952 -            throw new InternalError("unexpected entry: " + entry);
   1.953 -        }
   1.954 -    }
   1.955 -
   1.956 -    /**
   1.957 -     * FieldReflector cache lookup key.  Keys are considered equal if they
   1.958 -     * refer to the same class and equivalent field formats.
   1.959 -     */
   1.960 -    private static class FieldReflectorKey extends WeakReference<Class<?>> {
   1.961 -
   1.962 -        private final String sigs;
   1.963 -        private final int hash;
   1.964 -        private final boolean nullClass;
   1.965 -
   1.966 -        FieldReflectorKey(Class<?> cl, ObjectStreamField[] fields,
   1.967 -                          ReferenceQueue<Class<?>> queue)
   1.968 -        {
   1.969 -            super(cl, queue);
   1.970 -            nullClass = (cl == null);
   1.971 -            StringBuilder sbuf = new StringBuilder();
   1.972 -            for (int i = 0; i < fields.length; i++) {
   1.973 -                ObjectStreamField f = fields[i];
   1.974 -                sbuf.append(f.getName()).append(f.getSignature());
   1.975 -            }
   1.976 -            sigs = sbuf.toString();
   1.977 -            hash = System.identityHashCode(cl) + sigs.hashCode();
   1.978 -        }
   1.979 -
   1.980 -        public int hashCode() {
   1.981 -            return hash;
   1.982 -        }
   1.983 -
   1.984 -        public boolean equals(Object obj) {
   1.985 -            if (obj == this) {
   1.986 -                return true;
   1.987 -            }
   1.988 -
   1.989 -            if (obj instanceof FieldReflectorKey) {
   1.990 -                FieldReflectorKey other = (FieldReflectorKey) obj;
   1.991 -                Class<?> referent;
   1.992 -                return (nullClass ? other.nullClass
   1.993 -                                  : ((referent = get()) != null) &&
   1.994 -                                    (referent == other.get())) &&
   1.995 -                    sigs.equals(other.sigs);
   1.996 -            } else {
   1.997 -                return false;
   1.998 -            }
   1.999 -        }
  1.1000 -    }
  1.1001 -
  1.1002 -    /**
  1.1003 -     * Matches given set of serializable fields with serializable fields
  1.1004 -     * obtained from the given local class descriptor (which contain bindings
  1.1005 -     * to reflective Field objects).  Returns list of ObjectStreamFields in
  1.1006 -     * which each ObjectStreamField whose signature matches that of a local
  1.1007 -     * field contains a Field object for that field; unmatched
  1.1008 -     * ObjectStreamFields contain null Field objects.  Shared/unshared settings
  1.1009 -     * of the returned ObjectStreamFields also reflect those of matched local
  1.1010 -     * ObjectStreamFields.  Throws InvalidClassException if unresolvable type
  1.1011 -     * conflicts exist between the two sets of fields.
  1.1012 -     */
  1.1013 -    private static ObjectStreamField[] matchFields(ObjectStreamField[] fields,
  1.1014 -                                                   ObjectStreamClass localDesc)
  1.1015 -        throws InvalidClassException
  1.1016 -    {
  1.1017 -        ObjectStreamField[] localFields = (localDesc != null) ?
  1.1018 -            localDesc.fields : NO_FIELDS;
  1.1019 -
  1.1020 -        /*
  1.1021 -         * Even if fields == localFields, we cannot simply return localFields
  1.1022 -         * here.  In previous implementations of serialization,
  1.1023 -         * ObjectStreamField.getType() returned Object.class if the
  1.1024 -         * ObjectStreamField represented a non-primitive field and belonged to
  1.1025 -         * a non-local class descriptor.  To preserve this (questionable)
  1.1026 -         * behavior, the ObjectStreamField instances returned by matchFields
  1.1027 -         * cannot report non-primitive types other than Object.class; hence
  1.1028 -         * localFields cannot be returned directly.
  1.1029 -         */
  1.1030 -
  1.1031 -        ObjectStreamField[] matches = new ObjectStreamField[fields.length];
  1.1032 -        for (int i = 0; i < fields.length; i++) {
  1.1033 -            ObjectStreamField f = fields[i], m = null;
  1.1034 -            for (int j = 0; j < localFields.length; j++) {
  1.1035 -                ObjectStreamField lf = localFields[j];
  1.1036 -                if (f.getName().equals(lf.getName())) {
  1.1037 -                    if ((f.isPrimitive() || lf.isPrimitive()) &&
  1.1038 -                        f.getTypeCode() != lf.getTypeCode())
  1.1039 -                    {
  1.1040 -                        throw new InvalidClassException(localDesc.name,
  1.1041 -                            "incompatible types for field " + f.getName());
  1.1042 -                    }
  1.1043 -                    if (lf.getField() != null) {
  1.1044 -                        m = new ObjectStreamField(
  1.1045 -                            lf.getField(), lf.isUnshared(), false);
  1.1046 -                    } else {
  1.1047 -                        m = new ObjectStreamField(
  1.1048 -                            lf.getName(), lf.getSignature(), lf.isUnshared());
  1.1049 -                    }
  1.1050 -                }
  1.1051 -            }
  1.1052 -            if (m == null) {
  1.1053 -                m = new ObjectStreamField(
  1.1054 -                    f.getName(), f.getSignature(), false);
  1.1055 -            }
  1.1056 -            m.setOffset(f.getOffset());
  1.1057 -            matches[i] = m;
  1.1058 -        }
  1.1059 -        return matches;
  1.1060 -    }
  1.1061 -
  1.1062 -    /**
  1.1063 -     * Removes from the specified map any keys that have been enqueued
  1.1064 -     * on the specified reference queue.
  1.1065 -     */
  1.1066 -    static void processQueue(ReferenceQueue<Class<?>> queue,
  1.1067 -                             ConcurrentMap<? extends
  1.1068 -                             WeakReference<Class<?>>, ?> map)
  1.1069 -    {
  1.1070 -        Reference<? extends Class<?>> ref;
  1.1071 -        while((ref = queue.poll()) != null) {
  1.1072 -            map.remove(ref);
  1.1073 -        }
  1.1074 -    }
  1.1075 -
  1.1076 -    /**
  1.1077 -     *  Weak key for Class objects.
  1.1078 -     *
  1.1079 -     **/
  1.1080 -    static class WeakClassKey extends WeakReference<Class<?>> {
  1.1081 -        /**
  1.1082 -         * saved value of the referent's identity hash code, to maintain
  1.1083 -         * a consistent hash code after the referent has been cleared
  1.1084 -         */
  1.1085 -        private final int hash;
  1.1086 -
  1.1087 -        /**
  1.1088 -         * Create a new WeakClassKey to the given object, registered
  1.1089 -         * with a queue.
  1.1090 -         */
  1.1091 -        WeakClassKey(Class<?> cl, ReferenceQueue<Class<?>> refQueue) {
  1.1092 -            super(cl, refQueue);
  1.1093 -            hash = System.identityHashCode(cl);
  1.1094 -        }
  1.1095 -
  1.1096 -        /**
  1.1097 -         * Returns the identity hash code of the original referent.
  1.1098 -         */
  1.1099 -        public int hashCode() {
  1.1100 -            return hash;
  1.1101 -        }
  1.1102 -
  1.1103 -        /**
  1.1104 -         * Returns true if the given object is this identical
  1.1105 -         * WeakClassKey instance, or, if this object's referent has not
  1.1106 -         * been cleared, if the given object is another WeakClassKey
  1.1107 -         * instance with the identical non-null referent as this one.
  1.1108 -         */
  1.1109 -        public boolean equals(Object obj) {
  1.1110 -            if (obj == this) {
  1.1111 -                return true;
  1.1112 -            }
  1.1113 -
  1.1114 -            if (obj instanceof WeakClassKey) {
  1.1115 -                Object referent = get();
  1.1116 -                return (referent != null) &&
  1.1117 -                       (referent == ((WeakClassKey) obj).get());
  1.1118 -            } else {
  1.1119 -                return false;
  1.1120 -            }
  1.1121 -        }
  1.1122 -    }
  1.1123  }