src/share/classes/com/sun/corba/se/impl/io/ObjectStreamClass.java

Thu, 31 Aug 2017 18:10:36 +0800

author
aoqi
date
Thu, 31 Aug 2017 18:10:36 +0800
changeset 748
6845b95cba6b
parent 615
8b0b643ffd42
parent 0
7ef37b2cdcad
child 1550
b9597bbca222
permissions
-rw-r--r--

merge

aoqi@0 1 /*
aoqi@0 2 * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved.
aoqi@0 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
aoqi@0 4 *
aoqi@0 5 * This code is free software; you can redistribute it and/or modify it
aoqi@0 6 * under the terms of the GNU General Public License version 2 only, as
aoqi@0 7 * published by the Free Software Foundation. Oracle designates this
aoqi@0 8 * particular file as subject to the "Classpath" exception as provided
aoqi@0 9 * by Oracle in the LICENSE file that accompanied this code.
aoqi@0 10 *
aoqi@0 11 * This code is distributed in the hope that it will be useful, but WITHOUT
aoqi@0 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
aoqi@0 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
aoqi@0 14 * version 2 for more details (a copy is included in the LICENSE file that
aoqi@0 15 * accompanied this code).
aoqi@0 16 *
aoqi@0 17 * You should have received a copy of the GNU General Public License version
aoqi@0 18 * 2 along with this work; if not, write to the Free Software Foundation,
aoqi@0 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
aoqi@0 20 *
aoqi@0 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
aoqi@0 22 * or visit www.oracle.com if you need additional information or have any
aoqi@0 23 * questions.
aoqi@0 24 */
aoqi@0 25 /*
aoqi@0 26 * Licensed Materials - Property of IBM
aoqi@0 27 * RMI-IIOP v1.0
aoqi@0 28 * Copyright IBM Corp. 1998 2012 All Rights Reserved
aoqi@0 29 *
aoqi@0 30 */
aoqi@0 31
aoqi@0 32 package com.sun.corba.se.impl.io;
aoqi@0 33
aoqi@0 34 import java.security.MessageDigest;
aoqi@0 35 import java.security.NoSuchAlgorithmException;
aoqi@0 36 import java.security.DigestOutputStream;
aoqi@0 37 import java.security.AccessController;
aoqi@0 38 import java.security.PrivilegedExceptionAction;
aoqi@0 39 import java.security.PrivilegedActionException;
aoqi@0 40 import java.security.PrivilegedAction;
aoqi@0 41
aoqi@0 42 import java.lang.reflect.Modifier;
aoqi@0 43 import java.lang.reflect.Array;
aoqi@0 44 import java.lang.reflect.Field;
aoqi@0 45 import java.lang.reflect.Member;
aoqi@0 46 import java.lang.reflect.Method;
aoqi@0 47 import java.lang.reflect.Constructor;
aoqi@0 48 import java.lang.reflect.Proxy;
aoqi@0 49 import java.lang.reflect.InvocationTargetException;
aoqi@0 50
aoqi@0 51 import java.io.IOException;
aoqi@0 52 import java.io.DataOutputStream;
aoqi@0 53 import java.io.ByteArrayOutputStream;
aoqi@0 54 import java.io.InvalidClassException;
aoqi@0 55 import java.io.Externalizable;
aoqi@0 56 import java.io.Serializable;
aoqi@0 57
aoqi@0 58 import java.util.Arrays;
aoqi@0 59 import java.util.Comparator;
aoqi@0 60
aoqi@0 61 import com.sun.corba.se.impl.util.RepositoryId;
aoqi@0 62
aoqi@0 63 import org.omg.CORBA.ValueMember;
aoqi@0 64
aoqi@0 65 import sun.corba.Bridge;
aoqi@0 66
aoqi@0 67 /**
aoqi@0 68 * A ObjectStreamClass describes a class that can be serialized to a stream
aoqi@0 69 * or a class that was serialized to a stream. It contains the name
aoqi@0 70 * and the serialVersionUID of the class.
aoqi@0 71 * <br>
aoqi@0 72 * The ObjectStreamClass for a specific class loaded in this Java VM can
aoqi@0 73 * be found using the lookup method.
aoqi@0 74 *
aoqi@0 75 * @author Roger Riggs
aoqi@0 76 * @since JDK1.1
aoqi@0 77 */
aoqi@0 78 public class ObjectStreamClass implements java.io.Serializable {
aoqi@0 79 private static final boolean DEBUG_SVUID = false ;
aoqi@0 80
aoqi@0 81 public static final long kDefaultUID = -1;
aoqi@0 82
aoqi@0 83 private static Object noArgsList[] = {};
aoqi@0 84 private static Class<?> noTypesList[] = {};
aoqi@0 85
aoqi@0 86 /** true if represents enum type */
aoqi@0 87 private boolean isEnum;
aoqi@0 88
aoqi@0 89 private static final Bridge bridge =
aoqi@0 90 AccessController.doPrivileged(
aoqi@0 91 new PrivilegedAction<Bridge>() {
aoqi@0 92 public Bridge run() {
aoqi@0 93 return Bridge.get() ;
aoqi@0 94 }
aoqi@0 95 }
aoqi@0 96 ) ;
aoqi@0 97
aoqi@0 98 /** Find the descriptor for a class that can be serialized. Null
aoqi@0 99 * is returned if the specified class does not implement
aoqi@0 100 * java.io.Serializable or java.io.Externalizable.
aoqi@0 101 */
aoqi@0 102 static final ObjectStreamClass lookup(Class<?> cl)
aoqi@0 103 {
aoqi@0 104 ObjectStreamClass desc = lookupInternal(cl);
aoqi@0 105 if (desc.isSerializable() || desc.isExternalizable())
aoqi@0 106 return desc;
aoqi@0 107 return null;
aoqi@0 108 }
aoqi@0 109
aoqi@0 110 /*
aoqi@0 111 * Find the class descriptor for the specified class.
aoqi@0 112 * Package access only so it can be called from ObjectIn/OutStream.
aoqi@0 113 */
aoqi@0 114 static ObjectStreamClass lookupInternal(Class<?> cl)
aoqi@0 115 {
aoqi@0 116 /* Synchronize on the hashtable so no two threads will do
aoqi@0 117 * this at the same time.
aoqi@0 118 */
aoqi@0 119 ObjectStreamClass desc = null;
aoqi@0 120 synchronized (descriptorFor) {
aoqi@0 121 /* Find the matching descriptor if it already known */
aoqi@0 122 desc = findDescriptorFor(cl);
aoqi@0 123 if (desc == null) {
aoqi@0 124 /* Check if it's serializable */
aoqi@0 125 boolean serializable = Serializable.class.isAssignableFrom(cl);
aoqi@0 126
aoqi@0 127 /* If the class is only Serializable,
aoqi@0 128 * lookup the descriptor for the superclass.
aoqi@0 129 */
aoqi@0 130 ObjectStreamClass superdesc = null;
aoqi@0 131 if (serializable) {
aoqi@0 132 Class<?> superclass = cl.getSuperclass();
aoqi@0 133 if (superclass != null)
aoqi@0 134 superdesc = lookup(superclass);
aoqi@0 135 }
aoqi@0 136
aoqi@0 137 /* Check if its' externalizable.
aoqi@0 138 * If it's Externalizable, clear the serializable flag.
aoqi@0 139 * Only one or the other may be set in the protocol.
aoqi@0 140 */
aoqi@0 141 boolean externalizable = false;
aoqi@0 142 if (serializable) {
aoqi@0 143 externalizable =
aoqi@0 144 ((superdesc != null) && superdesc.isExternalizable()) ||
aoqi@0 145 Externalizable.class.isAssignableFrom(cl);
aoqi@0 146 if (externalizable) {
aoqi@0 147 serializable = false;
aoqi@0 148 }
aoqi@0 149 }
aoqi@0 150
aoqi@0 151 /* Create a new version descriptor,
aoqi@0 152 * it put itself in the known table.
aoqi@0 153 */
aoqi@0 154 desc = new ObjectStreamClass(cl, superdesc,
aoqi@0 155 serializable, externalizable);
aoqi@0 156 }
aoqi@0 157 // Must always call init. See bug 4488137. This code was
aoqi@0 158 // incorrectly changed to return immediately on a non-null
aoqi@0 159 // cache result. That allowed threads to gain access to
aoqi@0 160 // unintialized instances.
aoqi@0 161 //
aoqi@0 162 // History: Note, the following init() call was originally within
aoqi@0 163 // the synchronization block, as it currently is now. Later, the
aoqi@0 164 // init() call was moved outside the synchronization block, and
aoqi@0 165 // the init() method used a private member variable lock, to
aoqi@0 166 // avoid performance problems. See bug 4165204. But that lead to
aoqi@0 167 // a deadlock situation, see bug 5104239. Hence, the init() method
aoqi@0 168 // has now been moved back into the synchronization block. The
aoqi@0 169 // right approach to solving these problems would be to rewrite
aoqi@0 170 // this class, based on the latest java.io.ObjectStreamClass.
aoqi@0 171 desc.init();
aoqi@0 172 }
aoqi@0 173 return desc;
aoqi@0 174 }
aoqi@0 175
aoqi@0 176 /**
aoqi@0 177 * The name of the class described by this descriptor.
aoqi@0 178 */
aoqi@0 179 public final String getName() {
aoqi@0 180 return name;
aoqi@0 181 }
aoqi@0 182
aoqi@0 183 /**
aoqi@0 184 * Return the serialVersionUID for this class.
aoqi@0 185 * The serialVersionUID defines a set of classes all with the same name
aoqi@0 186 * that have evolved from a common root class and agree to be serialized
aoqi@0 187 * and deserialized using a common format.
aoqi@0 188 */
aoqi@0 189 public static final long getSerialVersionUID( java.lang.Class<?> clazz) {
aoqi@0 190 ObjectStreamClass theosc = ObjectStreamClass.lookup( clazz );
aoqi@0 191 if( theosc != null )
aoqi@0 192 {
aoqi@0 193 return theosc.getSerialVersionUID( );
aoqi@0 194 }
aoqi@0 195 return 0;
aoqi@0 196 }
aoqi@0 197
aoqi@0 198 /**
aoqi@0 199 * Return the serialVersionUID for this class.
aoqi@0 200 * The serialVersionUID defines a set of classes all with the same name
aoqi@0 201 * that have evolved from a common root class and agree to be serialized
aoqi@0 202 * and deserialized using a common format.
aoqi@0 203 */
aoqi@0 204 public final long getSerialVersionUID() {
aoqi@0 205 return suid;
aoqi@0 206 }
aoqi@0 207
aoqi@0 208 /**
aoqi@0 209 * Return the serialVersionUID string for this class.
aoqi@0 210 * The serialVersionUID defines a set of classes all with the same name
aoqi@0 211 * that have evolved from a common root class and agree to be serialized
aoqi@0 212 * and deserialized using a common format.
aoqi@0 213 */
aoqi@0 214 public final String getSerialVersionUIDStr() {
aoqi@0 215 if (suidStr == null)
aoqi@0 216 suidStr = Long.toHexString(suid).toUpperCase();
aoqi@0 217 return suidStr;
aoqi@0 218 }
aoqi@0 219
aoqi@0 220 /**
aoqi@0 221 * Return the actual (computed) serialVersionUID for this class.
aoqi@0 222 */
aoqi@0 223 public static final long getActualSerialVersionUID( java.lang.Class<?> clazz )
aoqi@0 224 {
aoqi@0 225 ObjectStreamClass theosc = ObjectStreamClass.lookup( clazz );
aoqi@0 226 if( theosc != null )
aoqi@0 227 {
aoqi@0 228 return theosc.getActualSerialVersionUID( );
aoqi@0 229 }
aoqi@0 230 return 0;
aoqi@0 231 }
aoqi@0 232
aoqi@0 233 /**
aoqi@0 234 * Return the actual (computed) serialVersionUID for this class.
aoqi@0 235 */
aoqi@0 236 public final long getActualSerialVersionUID() {
aoqi@0 237 return actualSuid;
aoqi@0 238 }
aoqi@0 239
aoqi@0 240 /**
aoqi@0 241 * Return the actual (computed) serialVersionUID for this class.
aoqi@0 242 */
aoqi@0 243 public final String getActualSerialVersionUIDStr() {
aoqi@0 244 if (actualSuidStr == null)
aoqi@0 245 actualSuidStr = Long.toHexString(actualSuid).toUpperCase();
aoqi@0 246 return actualSuidStr;
aoqi@0 247 }
aoqi@0 248
aoqi@0 249 /**
aoqi@0 250 * Return the class in the local VM that this version is mapped to.
aoqi@0 251 * Null is returned if there is no corresponding local class.
aoqi@0 252 */
aoqi@0 253 public final Class<?> forClass() {
aoqi@0 254 return ofClass;
aoqi@0 255 }
aoqi@0 256
aoqi@0 257 /**
aoqi@0 258 * Return an array of the fields of this serializable class.
aoqi@0 259 * @return an array containing an element for each persistent
aoqi@0 260 * field of this class. Returns an array of length zero if
aoqi@0 261 * there are no fields.
aoqi@0 262 * @since JDK1.2
aoqi@0 263 */
aoqi@0 264 public ObjectStreamField[] getFields() {
aoqi@0 265 // Return a copy so the caller can't change the fields.
aoqi@0 266 if (fields.length > 0) {
aoqi@0 267 ObjectStreamField[] dup = new ObjectStreamField[fields.length];
aoqi@0 268 System.arraycopy(fields, 0, dup, 0, fields.length);
aoqi@0 269 return dup;
aoqi@0 270 } else {
aoqi@0 271 return fields;
aoqi@0 272 }
aoqi@0 273 }
aoqi@0 274
aoqi@0 275 public boolean hasField(ValueMember field)
aoqi@0 276 {
aoqi@0 277 try {
aoqi@0 278 for (int i = 0; i < fields.length; i++) {
aoqi@0 279 if (fields[i].getName().equals(field.name)) {
aoqi@0 280 if (fields[i].getSignature().equals(
aoqi@0 281 ValueUtility.getSignature(field)))
aoqi@0 282 return true;
aoqi@0 283 }
aoqi@0 284 }
aoqi@0 285 } catch (Exception exc) {
aoqi@0 286 // Ignore this; all we want to do is return false
aoqi@0 287 // Note that ValueUtility.getSignature can throw checked exceptions.
aoqi@0 288 }
aoqi@0 289
aoqi@0 290 return false;
aoqi@0 291 }
aoqi@0 292
aoqi@0 293 /* Avoid unnecessary allocations. */
aoqi@0 294 final ObjectStreamField[] getFieldsNoCopy() {
aoqi@0 295 return fields;
aoqi@0 296 }
aoqi@0 297
aoqi@0 298 /**
aoqi@0 299 * Get the field of this class by name.
aoqi@0 300 * @return The ObjectStreamField object of the named field or null if there
aoqi@0 301 * is no such named field.
aoqi@0 302 */
aoqi@0 303 public final ObjectStreamField getField(String name) {
aoqi@0 304 /* Binary search of fields by name.
aoqi@0 305 */
aoqi@0 306 for (int i = fields.length-1; i >= 0; i--) {
aoqi@0 307 if (name.equals(fields[i].getName())) {
aoqi@0 308 return fields[i];
aoqi@0 309 }
aoqi@0 310 }
aoqi@0 311 return null;
aoqi@0 312 }
aoqi@0 313
aoqi@0 314 public Serializable writeReplace(Serializable value) {
aoqi@0 315 if (writeReplaceObjectMethod != null) {
aoqi@0 316 try {
aoqi@0 317 return (Serializable) writeReplaceObjectMethod.invoke(value,noArgsList);
aoqi@0 318 } catch(Throwable t) {
aoqi@0 319 throw new RuntimeException(t);
aoqi@0 320 }
aoqi@0 321 }
aoqi@0 322 else return value;
aoqi@0 323 }
aoqi@0 324
aoqi@0 325 public Object readResolve(Object value) {
aoqi@0 326 if (readResolveObjectMethod != null) {
aoqi@0 327 try {
aoqi@0 328 return readResolveObjectMethod.invoke(value,noArgsList);
aoqi@0 329 } catch(Throwable t) {
aoqi@0 330 throw new RuntimeException(t);
aoqi@0 331 }
aoqi@0 332 }
aoqi@0 333 else return value;
aoqi@0 334 }
aoqi@0 335
aoqi@0 336 /**
aoqi@0 337 * Return a string describing this ObjectStreamClass.
aoqi@0 338 */
aoqi@0 339 public final String toString() {
aoqi@0 340 StringBuffer sb = new StringBuffer();
aoqi@0 341
aoqi@0 342 sb.append(name);
aoqi@0 343 sb.append(": static final long serialVersionUID = ");
aoqi@0 344 sb.append(Long.toString(suid));
aoqi@0 345 sb.append("L;");
aoqi@0 346 return sb.toString();
aoqi@0 347 }
aoqi@0 348
aoqi@0 349 /*
aoqi@0 350 * Create a new ObjectStreamClass from a loaded class.
aoqi@0 351 * Don't call this directly, call lookup instead.
aoqi@0 352 */
aoqi@0 353 private ObjectStreamClass(java.lang.Class<?> cl, ObjectStreamClass superdesc,
aoqi@0 354 boolean serial, boolean extern)
aoqi@0 355 {
aoqi@0 356 ofClass = cl; /* created from this class */
aoqi@0 357
aoqi@0 358 if (Proxy.isProxyClass(cl)) {
aoqi@0 359 forProxyClass = true;
aoqi@0 360 }
aoqi@0 361
aoqi@0 362 name = cl.getName();
aoqi@0 363 isEnum = Enum.class.isAssignableFrom(cl);
aoqi@0 364 superclass = superdesc;
aoqi@0 365 serializable = serial;
aoqi@0 366 if (!forProxyClass) {
aoqi@0 367 // proxy classes are never externalizable
aoqi@0 368 externalizable = extern;
aoqi@0 369 }
aoqi@0 370
aoqi@0 371 /*
aoqi@0 372 * Enter this class in the table of known descriptors.
aoqi@0 373 * Otherwise, when the fields are read it may recurse
aoqi@0 374 * trying to find the descriptor for itself.
aoqi@0 375 */
aoqi@0 376 insertDescriptorFor(this);
aoqi@0 377
aoqi@0 378 /*
aoqi@0 379 * The remainder of initialization occurs in init(), which is called
aoqi@0 380 * after the lock on the global class descriptor table has been
aoqi@0 381 * released.
aoqi@0 382 */
aoqi@0 383 }
aoqi@0 384
aoqi@0 385 private static final class PersistentFieldsValue
aoqi@0 386 extends ClassValue<ObjectStreamField[]> {
aoqi@0 387 PersistentFieldsValue() { }
aoqi@0 388
aoqi@0 389 protected ObjectStreamField[] computeValue(Class<?> type) {
aoqi@0 390 try {
aoqi@0 391 Field pf = type.getDeclaredField("serialPersistentFields");
aoqi@0 392 int mods = pf.getModifiers();
aoqi@0 393 if (Modifier.isPrivate(mods) && Modifier.isStatic(mods) &&
aoqi@0 394 Modifier.isFinal(mods)) {
aoqi@0 395 pf.setAccessible(true);
aoqi@0 396 java.io.ObjectStreamField[] fields =
aoqi@0 397 (java.io.ObjectStreamField[])pf.get(type);
aoqi@0 398 return translateFields(fields);
aoqi@0 399 }
aoqi@0 400 } catch (NoSuchFieldException | IllegalAccessException |
aoqi@0 401 IllegalArgumentException | ClassCastException e) {
aoqi@0 402 }
aoqi@0 403 return null;
aoqi@0 404 }
aoqi@0 405
aoqi@0 406 private static ObjectStreamField[] translateFields(
aoqi@0 407 java.io.ObjectStreamField[] fields) {
aoqi@0 408 ObjectStreamField[] translation =
aoqi@0 409 new ObjectStreamField[fields.length];
aoqi@0 410 for (int i = 0; i < fields.length; i++) {
aoqi@0 411 translation[i] = new ObjectStreamField(fields[i].getName(),
aoqi@0 412 fields[i].getType());
aoqi@0 413 }
aoqi@0 414 return translation;
aoqi@0 415 }
aoqi@0 416 }
aoqi@0 417
aoqi@0 418 private static final PersistentFieldsValue persistentFieldsValue =
aoqi@0 419 new PersistentFieldsValue();
aoqi@0 420
aoqi@0 421 /*
aoqi@0 422 * Initialize class descriptor. This method is only invoked on class
aoqi@0 423 * descriptors created via calls to lookupInternal(). This method is kept
aoqi@0 424 * separate from the ObjectStreamClass constructor so that lookupInternal
aoqi@0 425 * does not have to hold onto a global class descriptor table lock while the
aoqi@0 426 * class descriptor is being initialized (see bug 4165204).
aoqi@0 427 */
aoqi@0 428
aoqi@0 429
aoqi@0 430 private void init() {
aoqi@0 431 synchronized (lock) {
aoqi@0 432
aoqi@0 433 // See description at definition of initialized.
aoqi@0 434 if (initialized)
aoqi@0 435 return;
aoqi@0 436
aoqi@0 437 final Class<?> cl = ofClass;
aoqi@0 438
aoqi@0 439 if (!serializable ||
aoqi@0 440 externalizable ||
aoqi@0 441 forProxyClass ||
aoqi@0 442 name.equals("java.lang.String")){
aoqi@0 443 fields = NO_FIELDS;
aoqi@0 444 } else if (serializable) {
aoqi@0 445 /* Ask for permission to override field access checks.
aoqi@0 446 */
aoqi@0 447 AccessController.doPrivileged(new PrivilegedAction() {
aoqi@0 448 public Object run() {
aoqi@0 449 /* Fill in the list of persistent fields.
aoqi@0 450 * If it is declared, use the declared serialPersistentFields.
aoqi@0 451 * Otherwise, extract the fields from the class itself.
aoqi@0 452 */
aoqi@0 453 fields = persistentFieldsValue.get(cl);
aoqi@0 454
aoqi@0 455 if (fields == null) {
aoqi@0 456 /* Get all of the declared fields for this
aoqi@0 457 * Class. setAccessible on all fields so they
aoqi@0 458 * can be accessed later. Create a temporary
aoqi@0 459 * ObjectStreamField array to hold each
aoqi@0 460 * non-static, non-transient field. Then copy the
aoqi@0 461 * temporary array into an array of the correct
aoqi@0 462 * size once the number of fields is known.
aoqi@0 463 */
aoqi@0 464 Field[] actualfields = cl.getDeclaredFields();
aoqi@0 465
aoqi@0 466 int numFields = 0;
aoqi@0 467 ObjectStreamField[] tempFields =
aoqi@0 468 new ObjectStreamField[actualfields.length];
aoqi@0 469 for (int i = 0; i < actualfields.length; i++) {
aoqi@0 470 Field fld = actualfields[i] ;
aoqi@0 471 int modifiers = fld.getModifiers();
aoqi@0 472 if (!Modifier.isStatic(modifiers) &&
aoqi@0 473 !Modifier.isTransient(modifiers)) {
aoqi@0 474 fld.setAccessible(true) ;
aoqi@0 475 tempFields[numFields++] = new ObjectStreamField(fld);
aoqi@0 476 }
aoqi@0 477 }
aoqi@0 478
aoqi@0 479 fields = new ObjectStreamField[numFields];
aoqi@0 480 System.arraycopy(tempFields, 0, fields, 0, numFields);
aoqi@0 481
aoqi@0 482 } else {
aoqi@0 483 // For each declared persistent field, look for an actual
aoqi@0 484 // reflected Field. If there is one, make sure it's the correct
aoqi@0 485 // type and cache it in the ObjectStreamClass for that field.
aoqi@0 486 for (int j = fields.length-1; j >= 0; j--) {
aoqi@0 487 try {
aoqi@0 488 Field reflField = cl.getDeclaredField(fields[j].getName());
aoqi@0 489 if (fields[j].getType() == reflField.getType()) {
aoqi@0 490 reflField.setAccessible(true);
aoqi@0 491 fields[j].setField(reflField);
aoqi@0 492 }
aoqi@0 493 } catch (NoSuchFieldException e) {
aoqi@0 494 // Nothing to do
aoqi@0 495 }
aoqi@0 496 }
aoqi@0 497 }
aoqi@0 498 return null;
aoqi@0 499 }
aoqi@0 500 });
aoqi@0 501
aoqi@0 502 if (fields.length > 1)
aoqi@0 503 Arrays.sort(fields);
aoqi@0 504
aoqi@0 505 /* Set up field data for use while writing using the API api. */
aoqi@0 506 computeFieldInfo();
aoqi@0 507 }
aoqi@0 508
aoqi@0 509 /* Get the serialVersionUID from the class.
aoqi@0 510 * It uses the access override mechanism so make sure
aoqi@0 511 * the field objects is only used here.
aoqi@0 512 *
aoqi@0 513 * NonSerializable classes have a serialVerisonUID of 0L.
aoqi@0 514 */
aoqi@0 515 if (isNonSerializable() || isEnum) {
aoqi@0 516 suid = 0L;
aoqi@0 517 } else {
aoqi@0 518 // Lookup special Serializable members using reflection.
aoqi@0 519 AccessController.doPrivileged(new PrivilegedAction() {
aoqi@0 520 public Object run() {
aoqi@0 521 if (forProxyClass) {
aoqi@0 522 // proxy classes always have serialVersionUID of 0L
aoqi@0 523 suid = 0L;
aoqi@0 524 } else {
aoqi@0 525 try {
aoqi@0 526 final Field f = cl.getDeclaredField("serialVersionUID");
aoqi@0 527 int mods = f.getModifiers();
aoqi@0 528 // SerialBug 5: static final SUID should be read
aoqi@0 529 if (Modifier.isStatic(mods) && Modifier.isFinal(mods) ) {
aoqi@0 530 f.setAccessible(true);
aoqi@0 531 suid = f.getLong(cl);
aoqi@0 532 // SerialBug 2: should be computed after writeObject
aoqi@0 533 // actualSuid = computeStructuralUID(cl);
aoqi@0 534 } else {
aoqi@0 535 suid = _computeSerialVersionUID(cl);
aoqi@0 536 // SerialBug 2: should be computed after writeObject
aoqi@0 537 // actualSuid = computeStructuralUID(cl);
aoqi@0 538 }
aoqi@0 539 } catch (NoSuchFieldException ex) {
aoqi@0 540 suid = _computeSerialVersionUID(cl);
aoqi@0 541 // SerialBug 2: should be computed after writeObject
aoqi@0 542 // actualSuid = computeStructuralUID(cl);
aoqi@0 543 } catch (IllegalAccessException ex) {
aoqi@0 544 suid = _computeSerialVersionUID(cl);
aoqi@0 545 }
aoqi@0 546 }
aoqi@0 547
aoqi@0 548 writeReplaceObjectMethod = ObjectStreamClass.getInheritableMethod(cl,
aoqi@0 549 "writeReplace", noTypesList, Object.class);
aoqi@0 550
aoqi@0 551 readResolveObjectMethod = ObjectStreamClass.getInheritableMethod(cl,
aoqi@0 552 "readResolve", noTypesList, Object.class);
aoqi@0 553
aoqi@0 554 if (externalizable)
aoqi@0 555 cons = getExternalizableConstructor(cl) ;
aoqi@0 556 else
aoqi@0 557 cons = getSerializableConstructor(cl) ;
aoqi@0 558
aoqi@0 559 if (serializable && !forProxyClass) {
aoqi@0 560 /* Look for the writeObject method
aoqi@0 561 * Set the accessible flag on it here. ObjectOutputStream
aoqi@0 562 * will call it as necessary.
aoqi@0 563 */
aoqi@0 564 writeObjectMethod = getPrivateMethod( cl, "writeObject",
aoqi@0 565 new Class<?>[] { java.io.ObjectOutputStream.class }, Void.TYPE ) ;
aoqi@0 566 readObjectMethod = getPrivateMethod( cl, "readObject",
aoqi@0 567 new Class<?>[] { java.io.ObjectInputStream.class }, Void.TYPE ) ;
aoqi@0 568 }
aoqi@0 569 return null;
aoqi@0 570 }
aoqi@0 571 });
aoqi@0 572 }
aoqi@0 573
aoqi@0 574 // This call depends on a lot of information computed above!
aoqi@0 575 actualSuid = ObjectStreamClass.computeStructuralUID(this, cl);
aoqi@0 576
aoqi@0 577 // If we have a write object method, precompute the
aoqi@0 578 // RMI-IIOP stream format version 2 optional data
aoqi@0 579 // repository ID.
aoqi@0 580 if (hasWriteObject())
aoqi@0 581 rmiiiopOptionalDataRepId = computeRMIIIOPOptionalDataRepId();
aoqi@0 582
aoqi@0 583 // This must be done last.
aoqi@0 584 initialized = true;
aoqi@0 585 }
aoqi@0 586 }
aoqi@0 587
aoqi@0 588 /**
aoqi@0 589 * Returns non-static private method with given signature defined by given
aoqi@0 590 * class, or null if none found. Access checks are disabled on the
aoqi@0 591 * returned method (if any).
aoqi@0 592 */
aoqi@0 593 private static Method getPrivateMethod(Class<?> cl, String name,
aoqi@0 594 Class<?>[] argTypes,
aoqi@0 595 Class<?> returnType)
aoqi@0 596 {
aoqi@0 597 try {
aoqi@0 598 Method meth = cl.getDeclaredMethod(name, argTypes);
aoqi@0 599 meth.setAccessible(true);
aoqi@0 600 int mods = meth.getModifiers();
aoqi@0 601 return ((meth.getReturnType() == returnType) &&
aoqi@0 602 ((mods & Modifier.STATIC) == 0) &&
aoqi@0 603 ((mods & Modifier.PRIVATE) != 0)) ? meth : null;
aoqi@0 604 } catch (NoSuchMethodException ex) {
aoqi@0 605 return null;
aoqi@0 606 }
aoqi@0 607 }
aoqi@0 608
aoqi@0 609 // Specific to RMI-IIOP
aoqi@0 610 /**
aoqi@0 611 * Java to IDL ptc-02-01-12 1.5.1
aoqi@0 612 *
aoqi@0 613 * "The rep_id string passed to the start_value method must be
aoqi@0 614 * 'RMI:org.omg.custom.class:hashcode:suid' where class is the
aoqi@0 615 * fully-qualified name of the class whose writeObject method
aoqi@0 616 * is being invoked and hashcode and suid are the class's hashcode
aoqi@0 617 * and SUID."
aoqi@0 618 */
aoqi@0 619 private String computeRMIIIOPOptionalDataRepId() {
aoqi@0 620
aoqi@0 621 StringBuffer sbuf = new StringBuffer("RMI:org.omg.custom.");
aoqi@0 622 sbuf.append(RepositoryId.convertToISOLatin1(this.getName()));
aoqi@0 623 sbuf.append(':');
aoqi@0 624 sbuf.append(this.getActualSerialVersionUIDStr());
aoqi@0 625 sbuf.append(':');
aoqi@0 626 sbuf.append(this.getSerialVersionUIDStr());
aoqi@0 627
aoqi@0 628 return sbuf.toString();
aoqi@0 629 }
aoqi@0 630
aoqi@0 631 /**
aoqi@0 632 * This will return null if there is no writeObject method.
aoqi@0 633 */
aoqi@0 634 public final String getRMIIIOPOptionalDataRepId() {
aoqi@0 635 return rmiiiopOptionalDataRepId;
aoqi@0 636 }
aoqi@0 637
aoqi@0 638 /*
aoqi@0 639 * Create an empty ObjectStreamClass for a class about to be read.
aoqi@0 640 * This is separate from read so ObjectInputStream can assign the
aoqi@0 641 * wire handle early, before any nested ObjectStreamClass might
aoqi@0 642 * be read.
aoqi@0 643 */
aoqi@0 644 ObjectStreamClass(String n, long s) {
aoqi@0 645 name = n;
aoqi@0 646 suid = s;
aoqi@0 647 superclass = null;
aoqi@0 648 }
aoqi@0 649
aoqi@0 650
aoqi@0 651 /*
aoqi@0 652 * Set the class this version descriptor matches.
aoqi@0 653 * The base class name and serializable hash must match.
aoqi@0 654 * Fill in the reflected Fields that will be used
aoqi@0 655 * for reading.
aoqi@0 656 */
aoqi@0 657 final void setClass(Class<?> cl) throws InvalidClassException {
aoqi@0 658
aoqi@0 659 if (cl == null) {
aoqi@0 660 localClassDesc = null;
aoqi@0 661 ofClass = null;
aoqi@0 662 computeFieldInfo();
aoqi@0 663 return;
aoqi@0 664 }
aoqi@0 665
aoqi@0 666 localClassDesc = lookupInternal(cl);
aoqi@0 667 if (localClassDesc == null)
aoqi@0 668 // XXX I18N, logging needed
aoqi@0 669 throw new InvalidClassException(cl.getName(),
aoqi@0 670 "Local class not compatible");
aoqi@0 671 if (suid != localClassDesc.suid) {
aoqi@0 672
aoqi@0 673 /* Check for exceptional cases that allow mismatched suid. */
aoqi@0 674
aoqi@0 675 /* Allow adding Serializable or Externalizable
aoqi@0 676 * to a later release of the class.
aoqi@0 677 */
aoqi@0 678 boolean addedSerialOrExtern =
aoqi@0 679 isNonSerializable() || localClassDesc.isNonSerializable();
aoqi@0 680
aoqi@0 681 /* Disregard the serialVersionUID of an array
aoqi@0 682 * when name and cl.Name differ. If resolveClass() returns
aoqi@0 683 * an array with a different package name,
aoqi@0 684 * the serialVersionUIDs will not match since the fully
aoqi@0 685 * qualified array class is used in the
aoqi@0 686 * computation of the array's serialVersionUID. There is
aoqi@0 687 * no way to set a permanent serialVersionUID for an array type.
aoqi@0 688 */
aoqi@0 689
aoqi@0 690 boolean arraySUID = (cl.isArray() && ! cl.getName().equals(name));
aoqi@0 691
aoqi@0 692 if (! arraySUID && ! addedSerialOrExtern ) {
aoqi@0 693 // XXX I18N, logging needed
aoqi@0 694 throw new InvalidClassException(cl.getName(),
aoqi@0 695 "Local class not compatible:" +
aoqi@0 696 " stream classdesc serialVersionUID=" + suid +
aoqi@0 697 " local class serialVersionUID=" + localClassDesc.suid);
aoqi@0 698 }
aoqi@0 699 }
aoqi@0 700
aoqi@0 701 /* compare the class names, stripping off package names. */
aoqi@0 702 if (! compareClassNames(name, cl.getName(), '.'))
aoqi@0 703 // XXX I18N, logging needed
aoqi@0 704 throw new InvalidClassException(cl.getName(),
aoqi@0 705 "Incompatible local class name. " +
aoqi@0 706 "Expected class name compatible with " +
aoqi@0 707 name);
aoqi@0 708
aoqi@0 709 /*
aoqi@0 710 * Test that both implement either serializable or externalizable.
aoqi@0 711 */
aoqi@0 712
aoqi@0 713 // The next check is more generic, since it covers the
aoqi@0 714 // Proxy case, the JDK 1.3 serialization code has
aoqi@0 715 // both checks
aoqi@0 716 //if ((serializable && localClassDesc.externalizable) ||
aoqi@0 717 // (externalizable && localClassDesc.serializable))
aoqi@0 718 // throw new InvalidClassException(localCl.getName(),
aoqi@0 719 // "Serializable is incompatible with Externalizable");
aoqi@0 720
aoqi@0 721 if ((serializable != localClassDesc.serializable) ||
aoqi@0 722 (externalizable != localClassDesc.externalizable) ||
aoqi@0 723 (!serializable && !externalizable))
aoqi@0 724
aoqi@0 725 // XXX I18N, logging needed
aoqi@0 726 throw new InvalidClassException(cl.getName(),
aoqi@0 727 "Serialization incompatible with Externalization");
aoqi@0 728
aoqi@0 729 /* Set up the reflected Fields in the class where the value of each
aoqi@0 730 * field in this descriptor should be stored.
aoqi@0 731 * Each field in this ObjectStreamClass (the source) is located (by
aoqi@0 732 * name) in the ObjectStreamClass of the class(the destination).
aoqi@0 733 * In the usual (non-versioned case) the field is in both
aoqi@0 734 * descriptors and the types match, so the reflected Field is copied.
aoqi@0 735 * If the type does not match, a InvalidClass exception is thrown.
aoqi@0 736 * If the field is not present in the class, the reflected Field
aoqi@0 737 * remains null so the field will be read but discarded.
aoqi@0 738 * If extra fields are present in the class they are ignored. Their
aoqi@0 739 * values will be set to the default value by the object allocator.
aoqi@0 740 * Both the src and dest field list are sorted by type and name.
aoqi@0 741 */
aoqi@0 742
aoqi@0 743 ObjectStreamField[] destfield =
aoqi@0 744 (ObjectStreamField[])localClassDesc.fields;
aoqi@0 745 ObjectStreamField[] srcfield =
aoqi@0 746 (ObjectStreamField[])fields;
aoqi@0 747
aoqi@0 748 int j = 0;
aoqi@0 749 nextsrc:
aoqi@0 750 for (int i = 0; i < srcfield.length; i++ ) {
aoqi@0 751 /* Find this field in the dest*/
aoqi@0 752 for (int k = j; k < destfield.length; k++) {
aoqi@0 753 if (srcfield[i].getName().equals(destfield[k].getName())) {
aoqi@0 754 /* found match */
aoqi@0 755 if (srcfield[i].isPrimitive() &&
aoqi@0 756 !srcfield[i].typeEquals(destfield[k])) {
aoqi@0 757 // XXX I18N, logging needed
aoqi@0 758 throw new InvalidClassException(cl.getName(),
aoqi@0 759 "The type of field " +
aoqi@0 760 srcfield[i].getName() +
aoqi@0 761 " of class " + name +
aoqi@0 762 " is incompatible.");
aoqi@0 763 }
aoqi@0 764
aoqi@0 765 /* Skip over any fields in the dest that are not in the src */
aoqi@0 766 j = k;
aoqi@0 767
aoqi@0 768 srcfield[i].setField(destfield[j].getField());
aoqi@0 769 // go on to the next source field
aoqi@0 770 continue nextsrc;
aoqi@0 771 }
aoqi@0 772 }
aoqi@0 773 }
aoqi@0 774
aoqi@0 775 /* Set up field data for use while reading from the input stream. */
aoqi@0 776 computeFieldInfo();
aoqi@0 777
aoqi@0 778 /* Remember the class this represents */
aoqi@0 779 ofClass = cl;
aoqi@0 780
aoqi@0 781 /* get the cache of these methods from the local class
aoqi@0 782 * implementation.
aoqi@0 783 */
aoqi@0 784 readObjectMethod = localClassDesc.readObjectMethod;
aoqi@0 785 readResolveObjectMethod = localClassDesc.readResolveObjectMethod;
aoqi@0 786 }
aoqi@0 787
aoqi@0 788 /* Compare the base class names of streamName and localName.
aoqi@0 789 *
aoqi@0 790 * @return Return true iff the base class name compare.
aoqi@0 791 * @parameter streamName Fully qualified class name.
aoqi@0 792 * @parameter localName Fully qualified class name.
aoqi@0 793 * @parameter pkgSeparator class names use either '.' or '/'.
aoqi@0 794 *
aoqi@0 795 * Only compare base class name to allow package renaming.
aoqi@0 796 */
aoqi@0 797 static boolean compareClassNames(String streamName,
aoqi@0 798 String localName,
aoqi@0 799 char pkgSeparator) {
aoqi@0 800 /* compare the class names, stripping off package names. */
aoqi@0 801 int streamNameIndex = streamName.lastIndexOf(pkgSeparator);
aoqi@0 802 if (streamNameIndex < 0)
aoqi@0 803 streamNameIndex = 0;
aoqi@0 804
aoqi@0 805 int localNameIndex = localName.lastIndexOf(pkgSeparator);
aoqi@0 806 if (localNameIndex < 0)
aoqi@0 807 localNameIndex = 0;
aoqi@0 808
aoqi@0 809 return streamName.regionMatches(false, streamNameIndex,
aoqi@0 810 localName, localNameIndex,
aoqi@0 811 streamName.length() - streamNameIndex);
aoqi@0 812 }
aoqi@0 813
aoqi@0 814 /*
aoqi@0 815 * Compare the types of two class descriptors.
aoqi@0 816 * They match if they have the same class name and suid
aoqi@0 817 */
aoqi@0 818 final boolean typeEquals(ObjectStreamClass other) {
aoqi@0 819 return (suid == other.suid) &&
aoqi@0 820 compareClassNames(name, other.name, '.');
aoqi@0 821 }
aoqi@0 822
aoqi@0 823 /*
aoqi@0 824 * Return the superclass descriptor of this descriptor.
aoqi@0 825 */
aoqi@0 826 final void setSuperclass(ObjectStreamClass s) {
aoqi@0 827 superclass = s;
aoqi@0 828 }
aoqi@0 829
aoqi@0 830 /*
aoqi@0 831 * Return the superclass descriptor of this descriptor.
aoqi@0 832 */
aoqi@0 833 final ObjectStreamClass getSuperclass() {
aoqi@0 834 return superclass;
aoqi@0 835 }
aoqi@0 836
aoqi@0 837 /**
aoqi@0 838 * Return whether the class has a readObject method
aoqi@0 839 */
aoqi@0 840 final boolean hasReadObject() {
aoqi@0 841 return readObjectMethod != null;
aoqi@0 842 }
aoqi@0 843
aoqi@0 844 /*
aoqi@0 845 * Return whether the class has a writeObject method
aoqi@0 846 */
aoqi@0 847 final boolean hasWriteObject() {
aoqi@0 848 return writeObjectMethod != null ;
aoqi@0 849 }
aoqi@0 850
aoqi@0 851 /**
aoqi@0 852 * Returns when or not this class should be custom
aoqi@0 853 * marshaled (use chunking). This should happen if
aoqi@0 854 * it is Externalizable OR if it or
aoqi@0 855 * any of its superclasses has a writeObject method,
aoqi@0 856 */
aoqi@0 857 final boolean isCustomMarshaled() {
aoqi@0 858 return (hasWriteObject() || isExternalizable())
aoqi@0 859 || (superclass != null && superclass.isCustomMarshaled());
aoqi@0 860 }
aoqi@0 861
aoqi@0 862 /*
aoqi@0 863 * Return true if all instances of 'this' Externalizable class
aoqi@0 864 * are written in block-data mode from the stream that 'this' was read
aoqi@0 865 * from. <p>
aoqi@0 866 *
aoqi@0 867 * In JDK 1.1, all Externalizable instances are not written
aoqi@0 868 * in block-data mode.
aoqi@0 869 * In JDK 1.2, all Externalizable instances, by default, are written
aoqi@0 870 * in block-data mode and the Externalizable instance is terminated with
aoqi@0 871 * tag TC_ENDBLOCKDATA. Change enabled the ability to skip Externalizable
aoqi@0 872 * instances.
aoqi@0 873 *
aoqi@0 874 * IMPLEMENTATION NOTE:
aoqi@0 875 * This should have been a mode maintained per stream; however,
aoqi@0 876 * for compatibility reasons, it was only possible to record
aoqi@0 877 * this change per class. All Externalizable classes within
aoqi@0 878 * a given stream should either have this mode enabled or
aoqi@0 879 * disabled. This is enforced by not allowing the PROTOCOL_VERSION
aoqi@0 880 * of a stream to he changed after any objects have been written.
aoqi@0 881 *
aoqi@0 882 * @see ObjectOutputStream#useProtocolVersion
aoqi@0 883 * @see ObjectStreamConstants#PROTOCOL_VERSION_1
aoqi@0 884 * @see ObjectStreamConstants#PROTOCOL_VERSION_2
aoqi@0 885 *
aoqi@0 886 * @since JDK 1.2
aoqi@0 887 */
aoqi@0 888 boolean hasExternalizableBlockDataMode() {
aoqi@0 889 return hasExternalizableBlockData;
aoqi@0 890 }
aoqi@0 891
aoqi@0 892 /**
aoqi@0 893 * Creates a new instance of the represented class. If the class is
aoqi@0 894 * externalizable, invokes its public no-arg constructor; otherwise, if the
aoqi@0 895 * class is serializable, invokes the no-arg constructor of the first
aoqi@0 896 * non-serializable superclass. Throws UnsupportedOperationException if
aoqi@0 897 * this class descriptor is not associated with a class, if the associated
aoqi@0 898 * class is non-serializable or if the appropriate no-arg constructor is
aoqi@0 899 * inaccessible/unavailable.
aoqi@0 900 */
aoqi@0 901 Object newInstance()
aoqi@0 902 throws InstantiationException, InvocationTargetException,
aoqi@0 903 UnsupportedOperationException
aoqi@0 904 {
aoqi@0 905 if (cons != null) {
aoqi@0 906 try {
aoqi@0 907 return cons.newInstance(new Object[0]);
aoqi@0 908 } catch (IllegalAccessException ex) {
aoqi@0 909 // should not occur, as access checks have been suppressed
aoqi@0 910 InternalError ie = new InternalError();
aoqi@0 911 ie.initCause( ex ) ;
aoqi@0 912 throw ie ;
aoqi@0 913 }
aoqi@0 914 } else {
aoqi@0 915 throw new UnsupportedOperationException();
aoqi@0 916 }
aoqi@0 917 }
aoqi@0 918
aoqi@0 919 /**
aoqi@0 920 * Returns public no-arg constructor of given class, or null if none found.
aoqi@0 921 * Access checks are disabled on the returned constructor (if any), since
aoqi@0 922 * the defining class may still be non-public.
aoqi@0 923 */
aoqi@0 924 private static Constructor getExternalizableConstructor(Class<?> cl) {
aoqi@0 925 try {
aoqi@0 926 Constructor cons = cl.getDeclaredConstructor(new Class<?>[0]);
aoqi@0 927 cons.setAccessible(true);
aoqi@0 928 return ((cons.getModifiers() & Modifier.PUBLIC) != 0) ?
aoqi@0 929 cons : null;
aoqi@0 930 } catch (NoSuchMethodException ex) {
aoqi@0 931 return null;
aoqi@0 932 }
aoqi@0 933 }
aoqi@0 934
aoqi@0 935 /**
aoqi@0 936 * Returns subclass-accessible no-arg constructor of first non-serializable
aoqi@0 937 * superclass, or null if none found. Access checks are disabled on the
aoqi@0 938 * returned constructor (if any).
aoqi@0 939 */
aoqi@0 940 private static Constructor getSerializableConstructor(Class<?> cl) {
aoqi@0 941 Class<?> initCl = cl;
aoqi@0 942 while (Serializable.class.isAssignableFrom(initCl)) {
aoqi@0 943 if ((initCl = initCl.getSuperclass()) == null) {
aoqi@0 944 return null;
aoqi@0 945 }
aoqi@0 946 }
aoqi@0 947 try {
aoqi@0 948 Constructor cons = initCl.getDeclaredConstructor(new Class<?>[0]);
aoqi@0 949 int mods = cons.getModifiers();
aoqi@0 950 if ((mods & Modifier.PRIVATE) != 0 ||
aoqi@0 951 ((mods & (Modifier.PUBLIC | Modifier.PROTECTED)) == 0 &&
aoqi@0 952 !packageEquals(cl, initCl)))
aoqi@0 953 {
aoqi@0 954 return null;
aoqi@0 955 }
aoqi@0 956 cons = bridge.newConstructorForSerialization(cl, cons);
aoqi@0 957 cons.setAccessible(true);
aoqi@0 958 return cons;
aoqi@0 959 } catch (NoSuchMethodException ex) {
aoqi@0 960 return null;
aoqi@0 961 }
aoqi@0 962 }
aoqi@0 963
aoqi@0 964 /*
aoqi@0 965 * Return the ObjectStreamClass of the local class this one is based on.
aoqi@0 966 */
aoqi@0 967 final ObjectStreamClass localClassDescriptor() {
aoqi@0 968 return localClassDesc;
aoqi@0 969 }
aoqi@0 970
aoqi@0 971 /*
aoqi@0 972 * Get the Serializability of the class.
aoqi@0 973 */
aoqi@0 974 boolean isSerializable() {
aoqi@0 975 return serializable;
aoqi@0 976 }
aoqi@0 977
aoqi@0 978 /*
aoqi@0 979 * Get the externalizability of the class.
aoqi@0 980 */
aoqi@0 981 boolean isExternalizable() {
aoqi@0 982 return externalizable;
aoqi@0 983 }
aoqi@0 984
aoqi@0 985 boolean isNonSerializable() {
aoqi@0 986 return ! (externalizable || serializable);
aoqi@0 987 }
aoqi@0 988
aoqi@0 989 /*
aoqi@0 990 * Calculate the size of the array needed to store primitive data and the
aoqi@0 991 * number of object references to read when reading from the input
aoqi@0 992 * stream.
aoqi@0 993 */
aoqi@0 994 private void computeFieldInfo() {
aoqi@0 995 primBytes = 0;
aoqi@0 996 objFields = 0;
aoqi@0 997
aoqi@0 998 for (int i = 0; i < fields.length; i++ ) {
aoqi@0 999 switch (fields[i].getTypeCode()) {
aoqi@0 1000 case 'B':
aoqi@0 1001 case 'Z':
aoqi@0 1002 primBytes += 1;
aoqi@0 1003 break;
aoqi@0 1004 case 'C':
aoqi@0 1005 case 'S':
aoqi@0 1006 primBytes += 2;
aoqi@0 1007 break;
aoqi@0 1008
aoqi@0 1009 case 'I':
aoqi@0 1010 case 'F':
aoqi@0 1011 primBytes += 4;
aoqi@0 1012 break;
aoqi@0 1013 case 'J':
aoqi@0 1014 case 'D' :
aoqi@0 1015 primBytes += 8;
aoqi@0 1016 break;
aoqi@0 1017
aoqi@0 1018 case 'L':
aoqi@0 1019 case '[':
aoqi@0 1020 objFields += 1;
aoqi@0 1021 break;
aoqi@0 1022 }
aoqi@0 1023 }
aoqi@0 1024 }
aoqi@0 1025
aoqi@0 1026 private static void msg( String str )
aoqi@0 1027 {
aoqi@0 1028 System.out.println( str ) ;
aoqi@0 1029 }
aoqi@0 1030
aoqi@0 1031 /* JDK 1.5 has introduced some new modifier bits (such as SYNTHETIC)
aoqi@0 1032 * that can affect the SVUID computation (see bug 4897937). These bits
aoqi@0 1033 * must be ignored, as otherwise interoperability with ORBs in earlier
aoqi@0 1034 * JDK versions can be compromised. I am adding these masks for this
aoqi@0 1035 * purpose as discussed in the CCC for this bug (see http://ccc.sfbay/4897937).
aoqi@0 1036 */
aoqi@0 1037
aoqi@0 1038 public static final int CLASS_MASK = Modifier.PUBLIC | Modifier.FINAL |
aoqi@0 1039 Modifier.INTERFACE | Modifier.ABSTRACT ;
aoqi@0 1040 public static final int FIELD_MASK = Modifier.PUBLIC | Modifier.PRIVATE |
aoqi@0 1041 Modifier.PROTECTED | Modifier.STATIC | Modifier.FINAL |
aoqi@0 1042 Modifier.TRANSIENT | Modifier.VOLATILE ;
aoqi@0 1043 public static final int METHOD_MASK = Modifier.PUBLIC | Modifier.PRIVATE |
aoqi@0 1044 Modifier.PROTECTED | Modifier.STATIC | Modifier.FINAL |
aoqi@0 1045 Modifier.SYNCHRONIZED | Modifier.NATIVE | Modifier.ABSTRACT |
aoqi@0 1046 Modifier.STRICT ;
aoqi@0 1047
aoqi@0 1048 /*
aoqi@0 1049 * Compute a hash for the specified class. Incrementally add
aoqi@0 1050 * items to the hash accumulating in the digest stream.
aoqi@0 1051 * Fold the hash into a long. Use the SHA secure hash function.
aoqi@0 1052 */
aoqi@0 1053 private static long _computeSerialVersionUID(Class<?> cl) {
aoqi@0 1054 if (DEBUG_SVUID)
aoqi@0 1055 msg( "Computing SerialVersionUID for " + cl ) ;
aoqi@0 1056 ByteArrayOutputStream devnull = new ByteArrayOutputStream(512);
aoqi@0 1057
aoqi@0 1058 long h = 0;
aoqi@0 1059 try {
aoqi@0 1060 MessageDigest md = MessageDigest.getInstance("SHA");
aoqi@0 1061 DigestOutputStream mdo = new DigestOutputStream(devnull, md);
aoqi@0 1062 DataOutputStream data = new DataOutputStream(mdo);
aoqi@0 1063
aoqi@0 1064 if (DEBUG_SVUID)
aoqi@0 1065 msg( "\twriteUTF( \"" + cl.getName() + "\" )" ) ;
aoqi@0 1066 data.writeUTF(cl.getName());
aoqi@0 1067
aoqi@0 1068 int classaccess = cl.getModifiers();
aoqi@0 1069 classaccess &= (Modifier.PUBLIC | Modifier.FINAL |
aoqi@0 1070 Modifier.INTERFACE | Modifier.ABSTRACT);
aoqi@0 1071
aoqi@0 1072 /* Workaround for javac bug that only set ABSTRACT for
aoqi@0 1073 * interfaces if the interface had some methods.
aoqi@0 1074 * The ABSTRACT bit reflects that the number of methods > 0.
aoqi@0 1075 * This is required so correct hashes can be computed
aoqi@0 1076 * for existing class files.
aoqi@0 1077 * Previously this hack was previously present in the VM.
aoqi@0 1078 */
aoqi@0 1079 Method[] method = cl.getDeclaredMethods();
aoqi@0 1080 if ((classaccess & Modifier.INTERFACE) != 0) {
aoqi@0 1081 classaccess &= (~Modifier.ABSTRACT);
aoqi@0 1082 if (method.length > 0) {
aoqi@0 1083 classaccess |= Modifier.ABSTRACT;
aoqi@0 1084 }
aoqi@0 1085 }
aoqi@0 1086
aoqi@0 1087 // Mask out any post-1.4 attributes
aoqi@0 1088 classaccess &= CLASS_MASK ;
aoqi@0 1089
aoqi@0 1090 if (DEBUG_SVUID)
aoqi@0 1091 msg( "\twriteInt( " + classaccess + " ) " ) ;
aoqi@0 1092 data.writeInt(classaccess);
aoqi@0 1093
aoqi@0 1094 /*
aoqi@0 1095 * Get the list of interfaces supported,
aoqi@0 1096 * Accumulate their names their names in Lexical order
aoqi@0 1097 * and add them to the hash
aoqi@0 1098 */
aoqi@0 1099 if (!cl.isArray()) {
aoqi@0 1100 /* In 1.2fcs, getInterfaces() was modified to return
aoqi@0 1101 * {java.lang.Cloneable, java.io.Serializable} when
aoqi@0 1102 * called on array classes. These values would upset
aoqi@0 1103 * the computation of the hash, so we explicitly omit
aoqi@0 1104 * them from its computation.
aoqi@0 1105 */
aoqi@0 1106
aoqi@0 1107 Class<?> interfaces[] = cl.getInterfaces();
aoqi@0 1108 Arrays.sort(interfaces, compareClassByName);
aoqi@0 1109
aoqi@0 1110 for (int i = 0; i < interfaces.length; i++) {
aoqi@0 1111 if (DEBUG_SVUID)
aoqi@0 1112 msg( "\twriteUTF( \"" + interfaces[i].getName() + "\" ) " ) ;
aoqi@0 1113 data.writeUTF(interfaces[i].getName());
aoqi@0 1114 }
aoqi@0 1115 }
aoqi@0 1116
aoqi@0 1117 /* Sort the field names to get a deterministic order */
aoqi@0 1118 Field[] field = cl.getDeclaredFields();
aoqi@0 1119 Arrays.sort(field, compareMemberByName);
aoqi@0 1120
aoqi@0 1121 for (int i = 0; i < field.length; i++) {
aoqi@0 1122 Field f = field[i];
aoqi@0 1123
aoqi@0 1124 /* Include in the hash all fields except those that are
aoqi@0 1125 * private transient and private static.
aoqi@0 1126 */
aoqi@0 1127 int m = f.getModifiers();
aoqi@0 1128 if (Modifier.isPrivate(m) &&
aoqi@0 1129 (Modifier.isTransient(m) || Modifier.isStatic(m)))
aoqi@0 1130 continue;
aoqi@0 1131
aoqi@0 1132 if (DEBUG_SVUID)
aoqi@0 1133 msg( "\twriteUTF( \"" + f.getName() + "\" ) " ) ;
aoqi@0 1134 data.writeUTF(f.getName());
aoqi@0 1135
aoqi@0 1136 // Mask out any post-1.4 bits
aoqi@0 1137 m &= FIELD_MASK ;
aoqi@0 1138
aoqi@0 1139 if (DEBUG_SVUID)
aoqi@0 1140 msg( "\twriteInt( " + m + " ) " ) ;
aoqi@0 1141 data.writeInt(m);
aoqi@0 1142
aoqi@0 1143 if (DEBUG_SVUID)
aoqi@0 1144 msg( "\twriteUTF( \"" + getSignature(f.getType()) + "\" ) " ) ;
aoqi@0 1145 data.writeUTF(getSignature(f.getType()));
aoqi@0 1146 }
aoqi@0 1147
aoqi@0 1148 if (hasStaticInitializer(cl)) {
aoqi@0 1149 if (DEBUG_SVUID)
aoqi@0 1150 msg( "\twriteUTF( \"<clinit>\" ) " ) ;
aoqi@0 1151 data.writeUTF("<clinit>");
aoqi@0 1152
aoqi@0 1153 if (DEBUG_SVUID)
aoqi@0 1154 msg( "\twriteInt( " + Modifier.STATIC + " )" ) ;
aoqi@0 1155 data.writeInt(Modifier.STATIC); // TBD: what modifiers does it have
aoqi@0 1156
aoqi@0 1157 if (DEBUG_SVUID)
aoqi@0 1158 msg( "\twriteUTF( \"()V\" )" ) ;
aoqi@0 1159 data.writeUTF("()V");
aoqi@0 1160 }
aoqi@0 1161
aoqi@0 1162 /*
aoqi@0 1163 * Get the list of constructors including name and signature
aoqi@0 1164 * Sort lexically, add all except the private constructors
aoqi@0 1165 * to the hash with their access flags
aoqi@0 1166 */
aoqi@0 1167
aoqi@0 1168 MethodSignature[] constructors =
aoqi@0 1169 MethodSignature.removePrivateAndSort(cl.getDeclaredConstructors());
aoqi@0 1170 for (int i = 0; i < constructors.length; i++) {
aoqi@0 1171 MethodSignature c = constructors[i];
aoqi@0 1172 String mname = "<init>";
aoqi@0 1173 String desc = c.signature;
aoqi@0 1174 desc = desc.replace('/', '.');
aoqi@0 1175 if (DEBUG_SVUID)
aoqi@0 1176 msg( "\twriteUTF( \"" + mname + "\" )" ) ;
aoqi@0 1177 data.writeUTF(mname);
aoqi@0 1178
aoqi@0 1179 // mask out post-1.4 modifiers
aoqi@0 1180 int modifier = c.member.getModifiers() & METHOD_MASK ;
aoqi@0 1181
aoqi@0 1182 if (DEBUG_SVUID)
aoqi@0 1183 msg( "\twriteInt( " + modifier + " ) " ) ;
aoqi@0 1184 data.writeInt( modifier ) ;
aoqi@0 1185
aoqi@0 1186 if (DEBUG_SVUID)
aoqi@0 1187 msg( "\twriteUTF( \"" + desc+ "\" )" ) ;
aoqi@0 1188 data.writeUTF(desc);
aoqi@0 1189 }
aoqi@0 1190
aoqi@0 1191 /* Include in the hash all methods except those that are
aoqi@0 1192 * private transient and private static.
aoqi@0 1193 */
aoqi@0 1194 MethodSignature[] methods =
aoqi@0 1195 MethodSignature.removePrivateAndSort(method);
aoqi@0 1196 for (int i = 0; i < methods.length; i++ ) {
aoqi@0 1197 MethodSignature m = methods[i];
aoqi@0 1198 String desc = m.signature;
aoqi@0 1199 desc = desc.replace('/', '.');
aoqi@0 1200
aoqi@0 1201 if (DEBUG_SVUID)
aoqi@0 1202 msg( "\twriteUTF( \"" + m.member.getName()+ "\" )" ) ;
aoqi@0 1203 data.writeUTF(m.member.getName());
aoqi@0 1204
aoqi@0 1205 // mask out post-1.4 modifiers
aoqi@0 1206 int modifier = m.member.getModifiers() & METHOD_MASK ;
aoqi@0 1207
aoqi@0 1208 if (DEBUG_SVUID)
aoqi@0 1209 msg( "\twriteInt( " + modifier + " ) " ) ;
aoqi@0 1210 data.writeInt( modifier ) ;
aoqi@0 1211
aoqi@0 1212 if (DEBUG_SVUID)
aoqi@0 1213 msg( "\twriteUTF( \"" + desc + "\" )" ) ;
aoqi@0 1214 data.writeUTF(desc);
aoqi@0 1215 }
aoqi@0 1216
aoqi@0 1217 /* Compute the hash value for this class.
aoqi@0 1218 * Use only the first 64 bits of the hash.
aoqi@0 1219 */
aoqi@0 1220 data.flush();
aoqi@0 1221 byte hasharray[] = md.digest();
aoqi@0 1222 for (int i = 0; i < Math.min(8, hasharray.length); i++) {
aoqi@0 1223 h += (long)(hasharray[i] & 255) << (i * 8);
aoqi@0 1224 }
aoqi@0 1225 } catch (IOException ignore) {
aoqi@0 1226 /* can't happen, but be deterministic anyway. */
aoqi@0 1227 h = -1;
aoqi@0 1228 } catch (NoSuchAlgorithmException complain) {
aoqi@0 1229 SecurityException se = new SecurityException() ;
aoqi@0 1230 se.initCause( complain ) ;
aoqi@0 1231 throw se ;
aoqi@0 1232 }
aoqi@0 1233
aoqi@0 1234 return h;
aoqi@0 1235 }
aoqi@0 1236
aoqi@0 1237 private static long computeStructuralUID(com.sun.corba.se.impl.io.ObjectStreamClass osc, Class<?> cl) {
aoqi@0 1238 ByteArrayOutputStream devnull = new ByteArrayOutputStream(512);
aoqi@0 1239
aoqi@0 1240 long h = 0;
aoqi@0 1241 try {
aoqi@0 1242
aoqi@0 1243 if ((!java.io.Serializable.class.isAssignableFrom(cl)) ||
aoqi@0 1244 (cl.isInterface())){
aoqi@0 1245 return 0;
aoqi@0 1246 }
aoqi@0 1247
aoqi@0 1248 if (java.io.Externalizable.class.isAssignableFrom(cl)) {
aoqi@0 1249 return 1;
aoqi@0 1250 }
aoqi@0 1251
aoqi@0 1252 MessageDigest md = MessageDigest.getInstance("SHA");
aoqi@0 1253 DigestOutputStream mdo = new DigestOutputStream(devnull, md);
aoqi@0 1254 DataOutputStream data = new DataOutputStream(mdo);
aoqi@0 1255
aoqi@0 1256 // Get SUID of parent
aoqi@0 1257 Class<?> parent = cl.getSuperclass();
aoqi@0 1258 if ((parent != null))
aoqi@0 1259 // SerialBug 1; acc. to spec the one for
aoqi@0 1260 // java.lang.object
aoqi@0 1261 // should be computed and put
aoqi@0 1262 // && (parent != java.lang.Object.class))
aoqi@0 1263 {
aoqi@0 1264 //data.writeLong(computeSerialVersionUID(null,parent));
aoqi@0 1265 data.writeLong(computeStructuralUID(lookup(parent), parent));
aoqi@0 1266 }
aoqi@0 1267
aoqi@0 1268 if (osc.hasWriteObject())
aoqi@0 1269 data.writeInt(2);
aoqi@0 1270 else
aoqi@0 1271 data.writeInt(1);
aoqi@0 1272
aoqi@0 1273 // CORBA formal 00-11-03 10.6.2: For each field of the
aoqi@0 1274 // class that is mapped to IDL, sorted lexicographically
aoqi@0 1275 // by Java field name, in increasing order...
aoqi@0 1276 ObjectStreamField[] field = osc.getFields();
aoqi@0 1277 if (field.length > 1) {
aoqi@0 1278 Arrays.sort(field, compareObjStrFieldsByName);
aoqi@0 1279 }
aoqi@0 1280
aoqi@0 1281 // ...Java field name in UTF encoding, field
aoqi@0 1282 // descriptor, as defined by the JVM spec...
aoqi@0 1283 for (int i = 0; i < field.length; i++) {
aoqi@0 1284 data.writeUTF(field[i].getName());
aoqi@0 1285 data.writeUTF(field[i].getSignature());
aoqi@0 1286 }
aoqi@0 1287
aoqi@0 1288 /* Compute the hash value for this class.
aoqi@0 1289 * Use only the first 64 bits of the hash.
aoqi@0 1290 */
aoqi@0 1291 data.flush();
aoqi@0 1292 byte hasharray[] = md.digest();
aoqi@0 1293 // int minimum = Math.min(8, hasharray.length);
aoqi@0 1294 // SerialBug 3: SHA computation is wrong; for loop reversed
aoqi@0 1295 //for (int i = minimum; i > 0; i--)
aoqi@0 1296 for (int i = 0; i < Math.min(8, hasharray.length); i++) {
aoqi@0 1297 h += (long)(hasharray[i] & 255) << (i * 8);
aoqi@0 1298 }
aoqi@0 1299 } catch (IOException ignore) {
aoqi@0 1300 /* can't happen, but be deterministic anyway. */
aoqi@0 1301 h = -1;
aoqi@0 1302 } catch (NoSuchAlgorithmException complain) {
aoqi@0 1303 SecurityException se = new SecurityException();
aoqi@0 1304 se.initCause( complain ) ;
aoqi@0 1305 throw se ;
aoqi@0 1306 }
aoqi@0 1307 return h;
aoqi@0 1308 }
aoqi@0 1309
aoqi@0 1310 /**
aoqi@0 1311 * Compute the JVM signature for the class.
aoqi@0 1312 */
aoqi@0 1313 static String getSignature(Class<?> clazz) {
aoqi@0 1314 String type = null;
aoqi@0 1315 if (clazz.isArray()) {
aoqi@0 1316 Class<?> cl = clazz;
aoqi@0 1317 int dimensions = 0;
aoqi@0 1318 while (cl.isArray()) {
aoqi@0 1319 dimensions++;
aoqi@0 1320 cl = cl.getComponentType();
aoqi@0 1321 }
aoqi@0 1322 StringBuffer sb = new StringBuffer();
aoqi@0 1323 for (int i = 0; i < dimensions; i++) {
aoqi@0 1324 sb.append("[");
aoqi@0 1325 }
aoqi@0 1326 sb.append(getSignature(cl));
aoqi@0 1327 type = sb.toString();
aoqi@0 1328 } else if (clazz.isPrimitive()) {
aoqi@0 1329 if (clazz == Integer.TYPE) {
aoqi@0 1330 type = "I";
aoqi@0 1331 } else if (clazz == Byte.TYPE) {
aoqi@0 1332 type = "B";
aoqi@0 1333 } else if (clazz == Long.TYPE) {
aoqi@0 1334 type = "J";
aoqi@0 1335 } else if (clazz == Float.TYPE) {
aoqi@0 1336 type = "F";
aoqi@0 1337 } else if (clazz == Double.TYPE) {
aoqi@0 1338 type = "D";
aoqi@0 1339 } else if (clazz == Short.TYPE) {
aoqi@0 1340 type = "S";
aoqi@0 1341 } else if (clazz == Character.TYPE) {
aoqi@0 1342 type = "C";
aoqi@0 1343 } else if (clazz == Boolean.TYPE) {
aoqi@0 1344 type = "Z";
aoqi@0 1345 } else if (clazz == Void.TYPE) {
aoqi@0 1346 type = "V";
aoqi@0 1347 }
aoqi@0 1348 } else {
aoqi@0 1349 type = "L" + clazz.getName().replace('.', '/') + ";";
aoqi@0 1350 }
aoqi@0 1351 return type;
aoqi@0 1352 }
aoqi@0 1353
aoqi@0 1354 /*
aoqi@0 1355 * Compute the JVM method descriptor for the method.
aoqi@0 1356 */
aoqi@0 1357 static String getSignature(Method meth) {
aoqi@0 1358 StringBuffer sb = new StringBuffer();
aoqi@0 1359
aoqi@0 1360 sb.append("(");
aoqi@0 1361
aoqi@0 1362 Class<?>[] params = meth.getParameterTypes(); // avoid clone
aoqi@0 1363 for (int j = 0; j < params.length; j++) {
aoqi@0 1364 sb.append(getSignature(params[j]));
aoqi@0 1365 }
aoqi@0 1366 sb.append(")");
aoqi@0 1367 sb.append(getSignature(meth.getReturnType()));
aoqi@0 1368 return sb.toString();
aoqi@0 1369 }
aoqi@0 1370
aoqi@0 1371 /*
aoqi@0 1372 * Compute the JVM constructor descriptor for the constructor.
aoqi@0 1373 */
aoqi@0 1374 static String getSignature(Constructor cons) {
aoqi@0 1375 StringBuffer sb = new StringBuffer();
aoqi@0 1376
aoqi@0 1377 sb.append("(");
aoqi@0 1378
aoqi@0 1379 Class<?>[] params = cons.getParameterTypes(); // avoid clone
aoqi@0 1380 for (int j = 0; j < params.length; j++) {
aoqi@0 1381 sb.append(getSignature(params[j]));
aoqi@0 1382 }
aoqi@0 1383 sb.append(")V");
aoqi@0 1384 return sb.toString();
aoqi@0 1385 }
aoqi@0 1386
aoqi@0 1387 /*
aoqi@0 1388 * Cache of Class -> ClassDescriptor Mappings.
aoqi@0 1389 */
aoqi@0 1390 static private ObjectStreamClassEntry[] descriptorFor = new ObjectStreamClassEntry[61];
aoqi@0 1391
aoqi@0 1392 /*
aoqi@0 1393 * findDescriptorFor a Class. This looks in the cache for a
aoqi@0 1394 * mapping from Class -> ObjectStreamClass mappings. The hashCode
aoqi@0 1395 * of the Class is used for the lookup since the Class is the key.
aoqi@0 1396 * The entries are extended from java.lang.ref.SoftReference so the
aoqi@0 1397 * gc will be able to free them if needed.
aoqi@0 1398 */
aoqi@0 1399 private static ObjectStreamClass findDescriptorFor(Class<?> cl) {
aoqi@0 1400
aoqi@0 1401 int hash = cl.hashCode();
aoqi@0 1402 int index = (hash & 0x7FFFFFFF) % descriptorFor.length;
aoqi@0 1403 ObjectStreamClassEntry e;
aoqi@0 1404 ObjectStreamClassEntry prev;
aoqi@0 1405
aoqi@0 1406 /* Free any initial entries whose refs have been cleared */
aoqi@0 1407 while ((e = descriptorFor[index]) != null && e.get() == null) {
aoqi@0 1408 descriptorFor[index] = e.next;
aoqi@0 1409 }
aoqi@0 1410
aoqi@0 1411 /* Traverse the chain looking for a descriptor with ofClass == cl.
aoqi@0 1412 * unlink entries that are unresolved.
aoqi@0 1413 */
aoqi@0 1414 prev = e;
aoqi@0 1415 while (e != null ) {
aoqi@0 1416 ObjectStreamClass desc = (ObjectStreamClass)(e.get());
aoqi@0 1417 if (desc == null) {
aoqi@0 1418 // This entry has been cleared, unlink it
aoqi@0 1419 prev.next = e.next;
aoqi@0 1420 } else {
aoqi@0 1421 if (desc.ofClass == cl)
aoqi@0 1422 return desc;
aoqi@0 1423 prev = e;
aoqi@0 1424 }
aoqi@0 1425 e = e.next;
aoqi@0 1426 }
aoqi@0 1427 return null;
aoqi@0 1428 }
aoqi@0 1429
aoqi@0 1430 /*
aoqi@0 1431 * insertDescriptorFor a Class -> ObjectStreamClass mapping.
aoqi@0 1432 */
aoqi@0 1433 private static void insertDescriptorFor(ObjectStreamClass desc) {
aoqi@0 1434 // Make sure not already present
aoqi@0 1435 if (findDescriptorFor(desc.ofClass) != null) {
aoqi@0 1436 return;
aoqi@0 1437 }
aoqi@0 1438
aoqi@0 1439 int hash = desc.ofClass.hashCode();
aoqi@0 1440 int index = (hash & 0x7FFFFFFF) % descriptorFor.length;
aoqi@0 1441 ObjectStreamClassEntry e = new ObjectStreamClassEntry(desc);
aoqi@0 1442 e.next = descriptorFor[index];
aoqi@0 1443 descriptorFor[index] = e;
aoqi@0 1444 }
aoqi@0 1445
aoqi@0 1446 private static Field[] getDeclaredFields(final Class<?> clz) {
aoqi@0 1447 return (Field[]) AccessController.doPrivileged(new PrivilegedAction() {
aoqi@0 1448 public Object run() {
aoqi@0 1449 return clz.getDeclaredFields();
aoqi@0 1450 }
aoqi@0 1451 });
aoqi@0 1452 }
aoqi@0 1453
aoqi@0 1454
aoqi@0 1455 /*
aoqi@0 1456 * The name of this descriptor
aoqi@0 1457 */
aoqi@0 1458 private String name;
aoqi@0 1459
aoqi@0 1460 /*
aoqi@0 1461 * The descriptor of the supertype.
aoqi@0 1462 */
aoqi@0 1463 private ObjectStreamClass superclass;
aoqi@0 1464
aoqi@0 1465 /*
aoqi@0 1466 * Flags for Serializable and Externalizable.
aoqi@0 1467 */
aoqi@0 1468 private boolean serializable;
aoqi@0 1469 private boolean externalizable;
aoqi@0 1470
aoqi@0 1471 /*
aoqi@0 1472 * Array of persistent fields of this class, sorted by
aoqi@0 1473 * type and name.
aoqi@0 1474 */
aoqi@0 1475 private ObjectStreamField[] fields;
aoqi@0 1476
aoqi@0 1477 /*
aoqi@0 1478 * Class that is a descriptor for in this virtual machine.
aoqi@0 1479 */
aoqi@0 1480 private Class<?> ofClass;
aoqi@0 1481
aoqi@0 1482 /*
aoqi@0 1483 * True if descriptor for a proxy class.
aoqi@0 1484 */
aoqi@0 1485 boolean forProxyClass;
aoqi@0 1486
aoqi@0 1487
aoqi@0 1488 /*
aoqi@0 1489 * SerialVersionUID for this class.
aoqi@0 1490 */
aoqi@0 1491 private long suid = kDefaultUID;
aoqi@0 1492 private String suidStr = null;
aoqi@0 1493
aoqi@0 1494 /*
aoqi@0 1495 * Actual (computed) SerialVersionUID for this class.
aoqi@0 1496 */
aoqi@0 1497 private long actualSuid = kDefaultUID;
aoqi@0 1498 private String actualSuidStr = null;
aoqi@0 1499
aoqi@0 1500 /*
aoqi@0 1501 * The total number of bytes of primitive fields.
aoqi@0 1502 * The total number of object fields.
aoqi@0 1503 */
aoqi@0 1504 int primBytes;
aoqi@0 1505 int objFields;
aoqi@0 1506
aoqi@0 1507 /**
aoqi@0 1508 * Flag indicating whether or not this instance has
aoqi@0 1509 * successfully completed initialization. This is to
aoqi@0 1510 * try to fix bug 4373844. Working to move to
aoqi@0 1511 * reusing java.io.ObjectStreamClass for JDK 1.5.
aoqi@0 1512 */
aoqi@0 1513 private boolean initialized = false;
aoqi@0 1514
aoqi@0 1515 /* Internal lock object. */
aoqi@0 1516 private Object lock = new Object();
aoqi@0 1517
aoqi@0 1518 /* In JDK 1.1, external data was not written in block mode.
aoqi@0 1519 * As of JDK 1.2, external data is written in block data mode. This
aoqi@0 1520 * flag enables JDK 1.2 to be able to read JDK 1.1 written external data.
aoqi@0 1521 *
aoqi@0 1522 * @since JDK 1.2
aoqi@0 1523 */
aoqi@0 1524 private boolean hasExternalizableBlockData;
aoqi@0 1525 Method writeObjectMethod;
aoqi@0 1526 Method readObjectMethod;
aoqi@0 1527 private transient Method writeReplaceObjectMethod;
aoqi@0 1528 private transient Method readResolveObjectMethod;
aoqi@0 1529 private Constructor cons ;
aoqi@0 1530
aoqi@0 1531 /**
aoqi@0 1532 * Beginning in Java to IDL ptc/02-01-12, RMI-IIOP has a
aoqi@0 1533 * stream format version 2 which puts a fake valuetype around
aoqi@0 1534 * a Serializable's optional custom data. This valuetype has
aoqi@0 1535 * a special repository ID made from the Serializable's
aoqi@0 1536 * information which we are pre-computing and
aoqi@0 1537 * storing here.
aoqi@0 1538 */
aoqi@0 1539 private String rmiiiopOptionalDataRepId = null;
aoqi@0 1540
aoqi@0 1541 /*
aoqi@0 1542 * ObjectStreamClass that this one was built from.
aoqi@0 1543 */
aoqi@0 1544 private ObjectStreamClass localClassDesc;
aoqi@0 1545
aoqi@0 1546 /* Find out if the class has a static class initializer <clinit> */
aoqi@0 1547 private static Method hasStaticInitializerMethod = null;
aoqi@0 1548 /**
aoqi@0 1549 * Returns true if the given class defines a static initializer method,
aoqi@0 1550 * false otherwise.
aoqi@0 1551 */
aoqi@0 1552 private static boolean hasStaticInitializer(Class<?> cl) {
aoqi@0 1553 if (hasStaticInitializerMethod == null) {
aoqi@0 1554 Class<?> classWithThisMethod = null;
aoqi@0 1555
aoqi@0 1556 try {
aoqi@0 1557 if (classWithThisMethod == null)
aoqi@0 1558 classWithThisMethod = java.io.ObjectStreamClass.class;
aoqi@0 1559
aoqi@0 1560 hasStaticInitializerMethod =
aoqi@0 1561 classWithThisMethod.getDeclaredMethod("hasStaticInitializer",
aoqi@0 1562 new Class<?>[] { Class.class });
aoqi@0 1563 } catch (NoSuchMethodException ex) {
aoqi@0 1564 }
aoqi@0 1565
aoqi@0 1566 if (hasStaticInitializerMethod == null) {
aoqi@0 1567 // XXX I18N, logging needed
aoqi@0 1568 throw new InternalError("Can't find hasStaticInitializer method on "
aoqi@0 1569 + classWithThisMethod.getName());
aoqi@0 1570 }
aoqi@0 1571 hasStaticInitializerMethod.setAccessible(true);
aoqi@0 1572 }
aoqi@0 1573
aoqi@0 1574 try {
aoqi@0 1575 Boolean retval = (Boolean)
aoqi@0 1576 hasStaticInitializerMethod.invoke(null, new Object[] { cl });
aoqi@0 1577 return retval.booleanValue();
aoqi@0 1578 } catch (Exception ex) {
aoqi@0 1579 // XXX I18N, logging needed
aoqi@0 1580 InternalError ie = new InternalError( "Error invoking hasStaticInitializer" ) ;
aoqi@0 1581 ie.initCause( ex ) ;
aoqi@0 1582 throw ie ;
aoqi@0 1583 }
aoqi@0 1584 }
aoqi@0 1585
aoqi@0 1586
aoqi@0 1587 /** use serialVersionUID from JDK 1.1. for interoperability */
aoqi@0 1588 private static final long serialVersionUID = -6120832682080437368L;
aoqi@0 1589
aoqi@0 1590 /**
aoqi@0 1591 * Set serialPersistentFields of a Serializable class to this value to
aoqi@0 1592 * denote that the class has no Serializable fields.
aoqi@0 1593 */
aoqi@0 1594 public static final ObjectStreamField[] NO_FIELDS =
aoqi@0 1595 new ObjectStreamField[0];
aoqi@0 1596
aoqi@0 1597 /*
aoqi@0 1598 * Entries held in the Cache of known ObjectStreamClass objects.
aoqi@0 1599 * Entries are chained together with the same hash value (modulo array size).
aoqi@0 1600 */
aoqi@0 1601 private static class ObjectStreamClassEntry // extends java.lang.ref.SoftReference
aoqi@0 1602 {
aoqi@0 1603 ObjectStreamClassEntry(ObjectStreamClass c) {
aoqi@0 1604 //super(c);
aoqi@0 1605 this.c = c;
aoqi@0 1606 }
aoqi@0 1607 ObjectStreamClassEntry next;
aoqi@0 1608
aoqi@0 1609 public Object get()
aoqi@0 1610 {
aoqi@0 1611 return c;
aoqi@0 1612 }
aoqi@0 1613 private ObjectStreamClass c;
aoqi@0 1614 }
aoqi@0 1615
aoqi@0 1616 /*
aoqi@0 1617 * Comparator object for Classes and Interfaces
aoqi@0 1618 */
aoqi@0 1619 private static Comparator compareClassByName =
aoqi@0 1620 new CompareClassByName();
aoqi@0 1621
aoqi@0 1622 private static class CompareClassByName implements Comparator {
aoqi@0 1623 public int compare(Object o1, Object o2) {
aoqi@0 1624 Class<?> c1 = (Class)o1;
aoqi@0 1625 Class<?> c2 = (Class)o2;
aoqi@0 1626 return (c1.getName()).compareTo(c2.getName());
aoqi@0 1627 }
aoqi@0 1628 }
aoqi@0 1629
aoqi@0 1630 /**
aoqi@0 1631 * Comparator for ObjectStreamFields by name
aoqi@0 1632 */
aoqi@0 1633 private final static Comparator compareObjStrFieldsByName
aoqi@0 1634 = new CompareObjStrFieldsByName();
aoqi@0 1635
aoqi@0 1636 private static class CompareObjStrFieldsByName implements Comparator {
aoqi@0 1637 public int compare(Object o1, Object o2) {
aoqi@0 1638 ObjectStreamField osf1 = (ObjectStreamField)o1;
aoqi@0 1639 ObjectStreamField osf2 = (ObjectStreamField)o2;
aoqi@0 1640
aoqi@0 1641 return osf1.getName().compareTo(osf2.getName());
aoqi@0 1642 }
aoqi@0 1643 }
aoqi@0 1644
aoqi@0 1645 /*
aoqi@0 1646 * Comparator object for Members, Fields, and Methods
aoqi@0 1647 */
aoqi@0 1648 private static Comparator compareMemberByName =
aoqi@0 1649 new CompareMemberByName();
aoqi@0 1650
aoqi@0 1651 private static class CompareMemberByName implements Comparator {
aoqi@0 1652 public int compare(Object o1, Object o2) {
aoqi@0 1653 String s1 = ((Member)o1).getName();
aoqi@0 1654 String s2 = ((Member)o2).getName();
aoqi@0 1655
aoqi@0 1656 if (o1 instanceof Method) {
aoqi@0 1657 s1 += getSignature((Method)o1);
aoqi@0 1658 s2 += getSignature((Method)o2);
aoqi@0 1659 } else if (o1 instanceof Constructor) {
aoqi@0 1660 s1 += getSignature((Constructor)o1);
aoqi@0 1661 s2 += getSignature((Constructor)o2);
aoqi@0 1662 }
aoqi@0 1663 return s1.compareTo(s2);
aoqi@0 1664 }
aoqi@0 1665 }
aoqi@0 1666
aoqi@0 1667 /* It is expensive to recompute a method or constructor signature
aoqi@0 1668 many times, so compute it only once using this data structure. */
aoqi@0 1669 private static class MethodSignature implements Comparator {
aoqi@0 1670 Member member;
aoqi@0 1671 String signature; // cached parameter signature
aoqi@0 1672
aoqi@0 1673 /* Given an array of Method or Constructor members,
aoqi@0 1674 return a sorted array of the non-private members.*/
aoqi@0 1675 /* A better implementation would be to implement the returned data
aoqi@0 1676 structure as an insertion sorted link list.*/
aoqi@0 1677 static MethodSignature[] removePrivateAndSort(Member[] m) {
aoqi@0 1678 int numNonPrivate = 0;
aoqi@0 1679 for (int i = 0; i < m.length; i++) {
aoqi@0 1680 if (! Modifier.isPrivate(m[i].getModifiers())) {
aoqi@0 1681 numNonPrivate++;
aoqi@0 1682 }
aoqi@0 1683 }
aoqi@0 1684 MethodSignature[] cm = new MethodSignature[numNonPrivate];
aoqi@0 1685 int cmi = 0;
aoqi@0 1686 for (int i = 0; i < m.length; i++) {
aoqi@0 1687 if (! Modifier.isPrivate(m[i].getModifiers())) {
aoqi@0 1688 cm[cmi] = new MethodSignature(m[i]);
aoqi@0 1689 cmi++;
aoqi@0 1690 }
aoqi@0 1691 }
aoqi@0 1692 if (cmi > 0)
aoqi@0 1693 Arrays.sort(cm, cm[0]);
aoqi@0 1694 return cm;
aoqi@0 1695 }
aoqi@0 1696
aoqi@0 1697 /* Assumes that o1 and o2 are either both methods
aoqi@0 1698 or both constructors.*/
aoqi@0 1699 public int compare(Object o1, Object o2) {
aoqi@0 1700 /* Arrays.sort calls compare when o1 and o2 are equal.*/
aoqi@0 1701 if (o1 == o2)
aoqi@0 1702 return 0;
aoqi@0 1703
aoqi@0 1704 MethodSignature c1 = (MethodSignature)o1;
aoqi@0 1705 MethodSignature c2 = (MethodSignature)o2;
aoqi@0 1706
aoqi@0 1707 int result;
aoqi@0 1708 if (isConstructor()) {
aoqi@0 1709 result = c1.signature.compareTo(c2.signature);
aoqi@0 1710 } else { // is a Method.
aoqi@0 1711 result = c1.member.getName().compareTo(c2.member.getName());
aoqi@0 1712 if (result == 0)
aoqi@0 1713 result = c1.signature.compareTo(c2.signature);
aoqi@0 1714 }
aoqi@0 1715 return result;
aoqi@0 1716 }
aoqi@0 1717
aoqi@0 1718 final private boolean isConstructor() {
aoqi@0 1719 return member instanceof Constructor;
aoqi@0 1720 }
aoqi@0 1721 private MethodSignature(Member m) {
aoqi@0 1722 member = m;
aoqi@0 1723 if (isConstructor()) {
aoqi@0 1724 signature = ObjectStreamClass.getSignature((Constructor)m);
aoqi@0 1725 } else {
aoqi@0 1726 signature = ObjectStreamClass.getSignature((Method)m);
aoqi@0 1727 }
aoqi@0 1728 }
aoqi@0 1729 }
aoqi@0 1730
aoqi@0 1731 /**
aoqi@0 1732 * Returns non-static, non-abstract method with given signature provided it
aoqi@0 1733 * is defined by or accessible (via inheritance) by the given class, or
aoqi@0 1734 * null if no match found. Access checks are disabled on the returned
aoqi@0 1735 * method (if any).
aoqi@0 1736 *
aoqi@0 1737 * Copied from the Merlin java.io.ObjectStreamClass.
aoqi@0 1738 */
aoqi@0 1739 private static Method getInheritableMethod(Class<?> cl, String name,
aoqi@0 1740 Class<?>[] argTypes,
aoqi@0 1741 Class<?> returnType)
aoqi@0 1742 {
aoqi@0 1743 Method meth = null;
aoqi@0 1744 Class<?> defCl = cl;
aoqi@0 1745 while (defCl != null) {
aoqi@0 1746 try {
aoqi@0 1747 meth = defCl.getDeclaredMethod(name, argTypes);
aoqi@0 1748 break;
aoqi@0 1749 } catch (NoSuchMethodException ex) {
aoqi@0 1750 defCl = defCl.getSuperclass();
aoqi@0 1751 }
aoqi@0 1752 }
aoqi@0 1753
aoqi@0 1754 if ((meth == null) || (meth.getReturnType() != returnType)) {
aoqi@0 1755 return null;
aoqi@0 1756 }
aoqi@0 1757 meth.setAccessible(true);
aoqi@0 1758 int mods = meth.getModifiers();
aoqi@0 1759 if ((mods & (Modifier.STATIC | Modifier.ABSTRACT)) != 0) {
aoqi@0 1760 return null;
aoqi@0 1761 } else if ((mods & (Modifier.PUBLIC | Modifier.PROTECTED)) != 0) {
aoqi@0 1762 return meth;
aoqi@0 1763 } else if ((mods & Modifier.PRIVATE) != 0) {
aoqi@0 1764 return (cl == defCl) ? meth : null;
aoqi@0 1765 } else {
aoqi@0 1766 return packageEquals(cl, defCl) ? meth : null;
aoqi@0 1767 }
aoqi@0 1768 }
aoqi@0 1769
aoqi@0 1770 /**
aoqi@0 1771 * Returns true if classes are defined in the same package, false
aoqi@0 1772 * otherwise.
aoqi@0 1773 *
aoqi@0 1774 * Copied from the Merlin java.io.ObjectStreamClass.
aoqi@0 1775 */
aoqi@0 1776 private static boolean packageEquals(Class<?> cl1, Class<?> cl2) {
aoqi@0 1777 Package pkg1 = cl1.getPackage(), pkg2 = cl2.getPackage();
aoqi@0 1778 return ((pkg1 == pkg2) || ((pkg1 != null) && (pkg1.equals(pkg2))));
aoqi@0 1779 }
aoqi@0 1780 }

mercurial