src/share/classes/com/sun/corba/se/impl/orbutil/ObjectStreamClass_1_3_1.java

Tue, 06 Nov 2012 15:50:14 +0000

author
coffeys
date
Tue, 06 Nov 2012 15:50:14 +0000
changeset 446
f4f39d873b9a
parent 158
91006f157c46
child 615
8b0b643ffd42
permissions
-rw-r--r--

7201066: Change modifiers on unused fields
Reviewed-by: alanb, skoivu

duke@1 1 /*
coffeys@446 2 * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
duke@1 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
duke@1 4 *
duke@1 5 * This code is free software; you can redistribute it and/or modify it
duke@1 6 * under the terms of the GNU General Public License version 2 only, as
ohair@158 7 * published by the Free Software Foundation. Oracle designates this
duke@1 8 * particular file as subject to the "Classpath" exception as provided
ohair@158 9 * by Oracle in the LICENSE file that accompanied this code.
duke@1 10 *
duke@1 11 * This code is distributed in the hope that it will be useful, but WITHOUT
duke@1 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
duke@1 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
duke@1 14 * version 2 for more details (a copy is included in the LICENSE file that
duke@1 15 * accompanied this code).
duke@1 16 *
duke@1 17 * You should have received a copy of the GNU General Public License version
duke@1 18 * 2 along with this work; if not, write to the Free Software Foundation,
duke@1 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
duke@1 20 *
ohair@158 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
ohair@158 22 * or visit www.oracle.com if you need additional information or have any
ohair@158 23 * questions.
duke@1 24 */
duke@1 25 /*
duke@1 26 * Licensed Materials - Property of IBM
duke@1 27 * RMI-IIOP v1.0
duke@1 28 * Copyright IBM Corp. 1998 1999 All Rights Reserved
duke@1 29 *
duke@1 30 */
duke@1 31
duke@1 32 package com.sun.corba.se.impl.orbutil;
duke@1 33
duke@1 34 import java.security.MessageDigest;
duke@1 35 import java.security.NoSuchAlgorithmException;
duke@1 36 import java.security.DigestOutputStream;
duke@1 37 import java.security.AccessController;
duke@1 38 import java.security.PrivilegedExceptionAction;
duke@1 39 import java.security.PrivilegedActionException;
duke@1 40 import java.security.PrivilegedAction;
duke@1 41
duke@1 42 import java.lang.reflect.Modifier;
duke@1 43 import java.lang.reflect.Array;
duke@1 44 import java.lang.reflect.Field;
duke@1 45 import java.lang.reflect.Member;
duke@1 46 import java.lang.reflect.Method;
duke@1 47 import java.lang.reflect.Constructor;
duke@1 48 import java.lang.reflect.Proxy;
duke@1 49 import java.lang.reflect.InvocationTargetException;
duke@1 50
duke@1 51 import java.io.IOException;
duke@1 52 import java.io.DataOutputStream;
duke@1 53 import java.io.ByteArrayOutputStream;
duke@1 54 import java.io.InvalidClassException;
duke@1 55 import java.io.Serializable;
duke@1 56
duke@1 57 import java.util.Arrays;
duke@1 58 import java.util.Comparator;
duke@1 59 import java.util.Hashtable;
duke@1 60
duke@1 61 import org.omg.CORBA.ValueMember;
duke@1 62
duke@1 63 import com.sun.corba.se.impl.io.ValueUtility;
duke@1 64 import com.sun.corba.se.impl.io.ObjectStreamClass;
duke@1 65
duke@1 66 /**
duke@1 67 * This is duplicated here to preserve the JDK 1.3.1FCS behavior
duke@1 68 * of calculating the OMG hash code incorrectly when serialPersistentFields
duke@1 69 * is used, but some of the fields no longer exist in the class itself.
duke@1 70 *
duke@1 71 * We have to duplicate it since we aren't allowed to modify the
duke@1 72 * com.sun.corba.se.impl.io version further, and can't make it
duke@1 73 * public outside of its package for security reasons.
duke@1 74 */
duke@1 75 /**
duke@1 76 * A ObjectStreamClass_1_3_1 describes a class that can be serialized to a stream
duke@1 77 * or a class that was serialized to a stream. It contains the name
duke@1 78 * and the serialVersionUID of the class.
duke@1 79 * <br>
duke@1 80 * The ObjectStreamClass_1_3_1 for a specific class loaded in this Java VM can
duke@1 81 * be found using the lookup method.
duke@1 82 *
duke@1 83 * @author Roger Riggs
duke@1 84 * @since JDK1.1
duke@1 85 */
duke@1 86 public class ObjectStreamClass_1_3_1 implements java.io.Serializable {
duke@1 87
duke@1 88 public static final long kDefaultUID = -1;
duke@1 89
duke@1 90 private static Object noArgsList[] = {};
duke@1 91 private static Class noTypesList[] = {};
duke@1 92
duke@1 93 private static Hashtable translatedFields;
duke@1 94
duke@1 95 /** Find the descriptor for a class that can be serialized. Null
duke@1 96 * is returned if the specified class does not implement
duke@1 97 * java.io.Serializable or java.io.Externalizable.
duke@1 98 */
duke@1 99 static final ObjectStreamClass_1_3_1 lookup(Class cl)
duke@1 100 {
duke@1 101 ObjectStreamClass_1_3_1 desc = lookupInternal(cl);
duke@1 102 if (desc.isSerializable() || desc.isExternalizable())
duke@1 103 return desc;
duke@1 104 return null;
duke@1 105 }
duke@1 106
duke@1 107 /*
duke@1 108 * Find the class descriptor for the specified class.
duke@1 109 * Package access only so it can be called from ObjectIn/OutStream.
duke@1 110 */
duke@1 111 static ObjectStreamClass_1_3_1 lookupInternal(Class cl)
duke@1 112 {
duke@1 113 /* Synchronize on the hashtable so no two threads will do
duke@1 114 * this at the same time.
duke@1 115 */
duke@1 116 ObjectStreamClass_1_3_1 desc = null;
duke@1 117 synchronized (descriptorFor) {
duke@1 118 /* Find the matching descriptor if it already known */
duke@1 119 desc = findDescriptorFor(cl);
duke@1 120 if (desc != null) {
duke@1 121 return desc;
duke@1 122 }
duke@1 123
duke@1 124 /* Check if it's serializable */
duke@1 125 boolean serializable = classSerializable.isAssignableFrom(cl);
duke@1 126 /* If the class is only Serializable,
duke@1 127 * lookup the descriptor for the superclass.
duke@1 128 */
duke@1 129 ObjectStreamClass_1_3_1 superdesc = null;
duke@1 130 if (serializable) {
duke@1 131 Class superclass = cl.getSuperclass();
duke@1 132 if (superclass != null)
duke@1 133 superdesc = lookup(superclass);
duke@1 134 }
duke@1 135
duke@1 136 /* Check if its' externalizable.
duke@1 137 * If it's Externalizable, clear the serializable flag.
duke@1 138 * Only one or the other may be set in the protocol.
duke@1 139 */
duke@1 140 boolean externalizable = false;
duke@1 141 if (serializable) {
duke@1 142 externalizable =
duke@1 143 ((superdesc != null) && superdesc.isExternalizable()) ||
duke@1 144 classExternalizable.isAssignableFrom(cl);
duke@1 145 if (externalizable) {
duke@1 146 serializable = false;
duke@1 147 }
duke@1 148 }
duke@1 149
duke@1 150 /* Create a new version descriptor,
duke@1 151 * it put itself in the known table.
duke@1 152 */
duke@1 153 desc = new ObjectStreamClass_1_3_1(cl, superdesc,
duke@1 154 serializable, externalizable);
duke@1 155 }
duke@1 156 desc.init();
duke@1 157 return desc;
duke@1 158 }
duke@1 159
duke@1 160 /**
duke@1 161 * The name of the class described by this descriptor.
duke@1 162 */
duke@1 163 public final String getName() {
duke@1 164 return name;
duke@1 165 }
duke@1 166
duke@1 167 /**
duke@1 168 * Return the serialVersionUID for this class.
duke@1 169 * The serialVersionUID defines a set of classes all with the same name
duke@1 170 * that have evolved from a common root class and agree to be serialized
duke@1 171 * and deserialized using a common format.
duke@1 172 */
duke@1 173 public static final long getSerialVersionUID( java.lang.Class clazz) {
duke@1 174 ObjectStreamClass_1_3_1 theosc = ObjectStreamClass_1_3_1.lookup( clazz );
duke@1 175 if( theosc != null )
duke@1 176 {
duke@1 177 return theosc.getSerialVersionUID( );
duke@1 178 }
duke@1 179 return 0;
duke@1 180 }
duke@1 181
duke@1 182 /**
duke@1 183 * Return the serialVersionUID for this class.
duke@1 184 * The serialVersionUID defines a set of classes all with the same name
duke@1 185 * that have evolved from a common root class and agree to be serialized
duke@1 186 * and deserialized using a common format.
duke@1 187 */
duke@1 188 public final long getSerialVersionUID() {
duke@1 189 return suid;
duke@1 190 }
duke@1 191
duke@1 192 /**
duke@1 193 * Return the serialVersionUID string for this class.
duke@1 194 * The serialVersionUID defines a set of classes all with the same name
duke@1 195 * that have evolved from a common root class and agree to be serialized
duke@1 196 * and deserialized using a common format.
duke@1 197 */
duke@1 198 public final String getSerialVersionUIDStr() {
duke@1 199 if (suidStr == null)
duke@1 200 suidStr = Long.toHexString(suid).toUpperCase();
duke@1 201 return suidStr;
duke@1 202 }
duke@1 203
duke@1 204 /**
duke@1 205 * Return the actual (computed) serialVersionUID for this class.
duke@1 206 */
duke@1 207 public static final long getActualSerialVersionUID( java.lang.Class clazz )
duke@1 208 {
duke@1 209 ObjectStreamClass_1_3_1 theosc = ObjectStreamClass_1_3_1.lookup( clazz );
duke@1 210 if( theosc != null )
duke@1 211 {
duke@1 212 return theosc.getActualSerialVersionUID( );
duke@1 213 }
duke@1 214 return 0;
duke@1 215 }
duke@1 216
duke@1 217 /**
duke@1 218 * Return the actual (computed) serialVersionUID for this class.
duke@1 219 */
duke@1 220 public final long getActualSerialVersionUID() {
duke@1 221 return actualSuid;
duke@1 222 }
duke@1 223
duke@1 224 /**
duke@1 225 * Return the actual (computed) serialVersionUID for this class.
duke@1 226 */
duke@1 227 public final String getActualSerialVersionUIDStr() {
duke@1 228 if (actualSuidStr == null)
duke@1 229 actualSuidStr = Long.toHexString(actualSuid).toUpperCase();
duke@1 230 return actualSuidStr;
duke@1 231 }
duke@1 232
duke@1 233 /**
duke@1 234 * Return the class in the local VM that this version is mapped to.
duke@1 235 * Null is returned if there is no corresponding local class.
duke@1 236 */
duke@1 237 public final Class forClass() {
duke@1 238 return ofClass;
duke@1 239 }
duke@1 240
duke@1 241 /**
duke@1 242 * Return an array of the fields of this serializable class.
duke@1 243 * @return an array containing an element for each persistent
duke@1 244 * field of this class. Returns an array of length zero if
duke@1 245 * there are no fields.
duke@1 246 * @since JDK1.2
duke@1 247 */
duke@1 248 public ObjectStreamField[] getFields() {
duke@1 249 // Return a copy so the caller can't change the fields.
duke@1 250 if (fields.length > 0) {
duke@1 251 ObjectStreamField[] dup = new ObjectStreamField[fields.length];
duke@1 252 System.arraycopy(fields, 0, dup, 0, fields.length);
duke@1 253 return dup;
duke@1 254 } else {
duke@1 255 return fields;
duke@1 256 }
duke@1 257 }
duke@1 258
duke@1 259 public boolean hasField(ValueMember field){
duke@1 260
duke@1 261 for (int i = 0; i < fields.length; i++){
duke@1 262 try{
duke@1 263 if (fields[i].getName().equals(field.name)) {
duke@1 264
duke@1 265 if (fields[i].getSignature().equals(ValueUtility.getSignature(field)))
duke@1 266 return true;
duke@1 267 }
duke@1 268 }
duke@1 269 catch(Throwable t){}
duke@1 270 }
duke@1 271 return false;
duke@1 272 }
duke@1 273
duke@1 274 /* Avoid unnecessary allocations. */
duke@1 275 final ObjectStreamField[] getFieldsNoCopy() {
duke@1 276 return fields;
duke@1 277 }
duke@1 278
duke@1 279 /**
duke@1 280 * Get the field of this class by name.
duke@1 281 * @return The ObjectStreamField object of the named field or null if there
duke@1 282 * is no such named field.
duke@1 283 */
duke@1 284 public final ObjectStreamField getField(String name) {
duke@1 285 /* Binary search of fields by name.
duke@1 286 */
duke@1 287 for (int i = fields.length-1; i >= 0; i--) {
duke@1 288 if (name.equals(fields[i].getName())) {
duke@1 289 return fields[i];
duke@1 290 }
duke@1 291 }
duke@1 292 return null;
duke@1 293 }
duke@1 294
duke@1 295 public Serializable writeReplace(Serializable value) {
duke@1 296 if (writeReplaceObjectMethod != null) {
duke@1 297 try {
duke@1 298 return (Serializable) writeReplaceObjectMethod.invoke(value,noArgsList);
duke@1 299 }
duke@1 300 catch(Throwable t) {
duke@1 301 throw new RuntimeException(t.getMessage());
duke@1 302 }
duke@1 303 }
duke@1 304 else return value;
duke@1 305 }
duke@1 306
duke@1 307 public Object readResolve(Object value) {
duke@1 308 if (readResolveObjectMethod != null) {
duke@1 309 try {
duke@1 310 return readResolveObjectMethod.invoke(value,noArgsList);
duke@1 311 }
duke@1 312 catch(Throwable t) {
duke@1 313 throw new RuntimeException(t.getMessage());
duke@1 314 }
duke@1 315 }
duke@1 316 else return value;
duke@1 317 }
duke@1 318
duke@1 319 /**
duke@1 320 * Return a string describing this ObjectStreamClass_1_3_1.
duke@1 321 */
duke@1 322 public final String toString() {
duke@1 323 StringBuffer sb = new StringBuffer();
duke@1 324
duke@1 325 sb.append(name);
duke@1 326 sb.append(": static final long serialVersionUID = ");
duke@1 327 sb.append(Long.toString(suid));
duke@1 328 sb.append("L;");
duke@1 329 return sb.toString();
duke@1 330 }
duke@1 331
duke@1 332 /*
duke@1 333 * Create a new ObjectStreamClass_1_3_1 from a loaded class.
duke@1 334 * Don't call this directly, call lookup instead.
duke@1 335 */
duke@1 336 private ObjectStreamClass_1_3_1(java.lang.Class cl, ObjectStreamClass_1_3_1 superdesc,
duke@1 337 boolean serial, boolean extern)
duke@1 338 {
duke@1 339 ofClass = cl; /* created from this class */
duke@1 340
duke@1 341 if (Proxy.isProxyClass(cl)) {
duke@1 342 forProxyClass = true;
duke@1 343 }
duke@1 344
duke@1 345 name = cl.getName();
duke@1 346 superclass = superdesc;
duke@1 347 serializable = serial;
duke@1 348 if (!forProxyClass) {
duke@1 349 // proxy classes are never externalizable
duke@1 350 externalizable = extern;
duke@1 351 }
duke@1 352
duke@1 353 /*
duke@1 354 * Enter this class in the table of known descriptors.
duke@1 355 * Otherwise, when the fields are read it may recurse
duke@1 356 * trying to find the descriptor for itself.
duke@1 357 */
duke@1 358 insertDescriptorFor(this);
duke@1 359
duke@1 360 /*
duke@1 361 * The remainder of initialization occurs in init(), which is called
duke@1 362 * after the lock on the global class descriptor table has been
duke@1 363 * released.
duke@1 364 */
duke@1 365 }
duke@1 366
duke@1 367 /*
duke@1 368 * Initialize class descriptor. This method is only invoked on class
duke@1 369 * descriptors created via calls to lookupInternal(). This method is kept
duke@1 370 * separate from the ObjectStreamClass_1_3_1 constructor so that lookupInternal
duke@1 371 * does not have to hold onto a global class descriptor table lock while the
duke@1 372 * class descriptor is being initialized (see bug 4165204).
duke@1 373 */
duke@1 374
duke@1 375
duke@1 376 private void init() {
duke@1 377 synchronized (lock) {
duke@1 378
duke@1 379 final Class cl = ofClass;
duke@1 380
duke@1 381 if (fields != null) // already initialized
duke@1 382 return;
duke@1 383
duke@1 384
duke@1 385 if (!serializable ||
duke@1 386 externalizable ||
duke@1 387 forProxyClass ||
duke@1 388 name.equals("java.lang.String")) {
duke@1 389 fields = NO_FIELDS;
duke@1 390 } else if (serializable) {
duke@1 391
duke@1 392 /* Ask for permission to override field access checks.
duke@1 393 */
duke@1 394 AccessController.doPrivileged(new PrivilegedAction() {
duke@1 395 public Object run() {
duke@1 396 /* Fill in the list of persistent fields.
duke@1 397 * If it is declared, use the declared serialPersistentFields.
duke@1 398 * Otherwise, extract the fields from the class itself.
duke@1 399 */
duke@1 400 try {
duke@1 401 Field pf = cl.getDeclaredField("serialPersistentFields");
duke@1 402 // serial bug 7; the serialPersistentFields were not
duke@1 403 // being read and stored as Accessible bit was not set
duke@1 404 pf.setAccessible(true);
duke@1 405 // serial bug 7; need to find if the field is of type
duke@1 406 // java.io.ObjectStreamField
duke@1 407 java.io.ObjectStreamField[] f =
duke@1 408 (java.io.ObjectStreamField[])pf.get(cl);
duke@1 409 int mods = pf.getModifiers();
duke@1 410 if ((Modifier.isPrivate(mods)) &&
duke@1 411 (Modifier.isStatic(mods)) &&
duke@1 412 (Modifier.isFinal(mods)))
duke@1 413 {
duke@1 414 fields = (ObjectStreamField[])translateFields((Object[])pf.get(cl));
duke@1 415 }
duke@1 416 } catch (NoSuchFieldException e) {
duke@1 417 fields = null;
duke@1 418 } catch (IllegalAccessException e) {
duke@1 419 fields = null;
duke@1 420 } catch (IllegalArgumentException e) {
duke@1 421 fields = null;
duke@1 422 } catch (ClassCastException e) {
duke@1 423 /* Thrown if a field serialPersistentField exists
duke@1 424 * but it is not of type ObjectStreamField.
duke@1 425 */
duke@1 426 fields = null;
duke@1 427 }
duke@1 428
duke@1 429
duke@1 430 if (fields == null) {
duke@1 431 /* Get all of the declared fields for this
duke@1 432 * Class. setAccessible on all fields so they
duke@1 433 * can be accessed later. Create a temporary
duke@1 434 * ObjectStreamField array to hold each
duke@1 435 * non-static, non-transient field. Then copy the
duke@1 436 * temporary array into an array of the correct
duke@1 437 * size once the number of fields is known.
duke@1 438 */
duke@1 439 Field[] actualfields = cl.getDeclaredFields();
duke@1 440
duke@1 441 int numFields = 0;
duke@1 442 ObjectStreamField[] tempFields =
duke@1 443 new ObjectStreamField[actualfields.length];
duke@1 444 for (int i = 0; i < actualfields.length; i++) {
duke@1 445 int modifiers = actualfields[i].getModifiers();
duke@1 446 if (!Modifier.isStatic(modifiers) &&
duke@1 447 !Modifier.isTransient(modifiers)) {
duke@1 448 tempFields[numFields++] =
duke@1 449 new ObjectStreamField(actualfields[i]);
duke@1 450 }
duke@1 451 }
duke@1 452 fields = new ObjectStreamField[numFields];
duke@1 453 System.arraycopy(tempFields, 0, fields, 0, numFields);
duke@1 454
duke@1 455 } else {
duke@1 456 // For each declared persistent field, look for an actual
duke@1 457 // reflected Field. If there is one, make sure it's the correct
duke@1 458 // type and cache it in the ObjectStreamClass_1_3_1 for that field.
duke@1 459 for (int j = fields.length-1; j >= 0; j--) {
duke@1 460 try {
duke@1 461 Field reflField = cl.getDeclaredField(fields[j].getName());
duke@1 462 if (fields[j].getType() == reflField.getType()) {
duke@1 463 // reflField.setAccessible(true);
duke@1 464 fields[j].setField(reflField);
duke@1 465 }
duke@1 466 } catch (NoSuchFieldException e) {
duke@1 467 // Nothing to do
duke@1 468 }
duke@1 469 }
duke@1 470 }
duke@1 471 return null;
duke@1 472 }
duke@1 473 });
duke@1 474
duke@1 475 if (fields.length > 1)
duke@1 476 Arrays.sort(fields);
duke@1 477
duke@1 478 /* Set up field data for use while writing using the API api. */
duke@1 479 computeFieldInfo();
duke@1 480 }
duke@1 481
duke@1 482 /* Get the serialVersionUID from the class.
duke@1 483 * It uses the access override mechanism so make sure
duke@1 484 * the field objects is only used here.
duke@1 485 *
duke@1 486 * NonSerializable classes have a serialVerisonUID of 0L.
duke@1 487 */
duke@1 488 if (isNonSerializable()) {
duke@1 489 suid = 0L;
duke@1 490 } else {
duke@1 491 // Lookup special Serializable members using reflection.
duke@1 492 AccessController.doPrivileged(new PrivilegedAction() {
duke@1 493 public Object run() {
duke@1 494 if (forProxyClass) {
duke@1 495 // proxy classes always have serialVersionUID of 0L
duke@1 496 suid = 0L;
duke@1 497 } else {
duke@1 498 try {
duke@1 499 final Field f = cl.getDeclaredField("serialVersionUID");
duke@1 500 int mods = f.getModifiers();
duke@1 501 // SerialBug 5: static final SUID should be read
duke@1 502 if (Modifier.isStatic(mods) &&
duke@1 503 Modifier.isFinal(mods) ) {
duke@1 504 f.setAccessible(true);
duke@1 505 suid = f.getLong(cl);
duke@1 506 // get rid of native code
duke@1 507 // suid = getSerialVersionUIDField(cl);
duke@1 508 // SerialBug 2: should be computed after writeObject
duke@1 509 // actualSuid = computeStructuralUID(cl);
duke@1 510 } else {
duke@1 511 suid = ObjectStreamClass.getSerialVersionUID(cl);
duke@1 512 // SerialBug 2: should be computed after writeObject
duke@1 513 // actualSuid = computeStructuralUID(cl);
duke@1 514 }
duke@1 515 } catch (NoSuchFieldException ex) {
duke@1 516 suid = ObjectStreamClass.getSerialVersionUID(cl);
duke@1 517 // SerialBug 2: should be computed after writeObject
duke@1 518 // actualSuid = computeStructuralUID(cl);
duke@1 519 } catch (IllegalAccessException ex) {
duke@1 520 suid = ObjectStreamClass.getSerialVersionUID(cl);
duke@1 521 }
duke@1 522 }
duke@1 523
duke@1 524
duke@1 525 try {
duke@1 526 writeReplaceObjectMethod = cl.getDeclaredMethod("writeReplace", noTypesList);
duke@1 527 if (Modifier.isStatic(writeReplaceObjectMethod.getModifiers())) {
duke@1 528 writeReplaceObjectMethod = null;
duke@1 529 } else {
duke@1 530 writeReplaceObjectMethod.setAccessible(true);
duke@1 531 }
duke@1 532
duke@1 533 } catch (NoSuchMethodException e2) {
duke@1 534
duke@1 535 }
duke@1 536
duke@1 537 try {
duke@1 538 readResolveObjectMethod = cl.getDeclaredMethod("readResolve", noTypesList);
duke@1 539 if (Modifier.isStatic(readResolveObjectMethod.getModifiers())) {
duke@1 540 readResolveObjectMethod = null;
duke@1 541 } else {
duke@1 542 readResolveObjectMethod.setAccessible(true);
duke@1 543 }
duke@1 544
duke@1 545 } catch (NoSuchMethodException e2) {
duke@1 546
duke@1 547 }
duke@1 548
duke@1 549 /* Cache lookup of writeObject and readObject for
duke@1 550 * Serializable classes. (Do not lookup for
duke@1 551 * Externalizable)
duke@1 552 */
duke@1 553
duke@1 554 if (serializable && !forProxyClass) {
duke@1 555
duke@1 556 /* Look for the writeObject method
duke@1 557 * Set the accessible flag on it here. ObjectOutputStream
duke@1 558 * will call it as necessary.
duke@1 559 */
duke@1 560 try {
duke@1 561 Class[] args = {java.io.ObjectOutputStream.class};
duke@1 562 writeObjectMethod = cl.getDeclaredMethod("writeObject", args);
duke@1 563 hasWriteObjectMethod = true;
duke@1 564 int mods = writeObjectMethod.getModifiers();
duke@1 565
duke@1 566 // Method must be private and non-static
duke@1 567 if (!Modifier.isPrivate(mods) ||
duke@1 568 Modifier.isStatic(mods)) {
duke@1 569 writeObjectMethod = null;
duke@1 570 hasWriteObjectMethod = false;
duke@1 571 }
duke@1 572
duke@1 573 } catch (NoSuchMethodException e) {
duke@1 574 }
duke@1 575
duke@1 576 /* Look for the readObject method
duke@1 577 * set the access override and save the reference for
duke@1 578 * ObjectInputStream so it can all the method directly.
duke@1 579 */
duke@1 580 try {
duke@1 581 Class[] args = {java.io.ObjectInputStream.class};
duke@1 582 readObjectMethod = cl.getDeclaredMethod("readObject", args);
duke@1 583 int mods = readObjectMethod.getModifiers();
duke@1 584
duke@1 585 // Method must be private and non-static
duke@1 586 if (!Modifier.isPrivate(mods) ||
duke@1 587 Modifier.isStatic(mods)) {
duke@1 588 readObjectMethod = null;
duke@1 589 }
duke@1 590 } catch (NoSuchMethodException e) {
duke@1 591 }
duke@1 592 // Compute the structural UID. This must be done after the
duke@1 593 // calculation for writeObject. Fixed 4/20/2000, eea1
duke@1 594 // SerialBug 2: to have correct value in RepId
duke@1 595 }
duke@1 596 return null;
duke@1 597 }
duke@1 598 });
duke@1 599 }
duke@1 600
duke@1 601 actualSuid = computeStructuralUID(this, cl);
duke@1 602 }
duke@1 603
duke@1 604 }
duke@1 605
duke@1 606 /*
duke@1 607 * Create an empty ObjectStreamClass_1_3_1 for a class about to be read.
duke@1 608 * This is separate from read so ObjectInputStream can assign the
duke@1 609 * wire handle early, before any nested ObjectStreamClass_1_3_1 might
duke@1 610 * be read.
duke@1 611 */
duke@1 612 ObjectStreamClass_1_3_1(String n, long s) {
duke@1 613 name = n;
duke@1 614 suid = s;
duke@1 615 superclass = null;
duke@1 616 }
duke@1 617
duke@1 618 private static Object[] translateFields(Object objs[])
duke@1 619 throws NoSuchFieldException {
duke@1 620 try{
duke@1 621 java.io.ObjectStreamField fields[] = (java.io.ObjectStreamField[])objs;
duke@1 622 Object translation[] = null;
duke@1 623
duke@1 624 if (translatedFields == null)
duke@1 625 translatedFields = new Hashtable();
duke@1 626
duke@1 627 translation = (Object[])translatedFields.get(fields);
duke@1 628
duke@1 629 if (translation != null)
duke@1 630 return translation;
duke@1 631 else {
duke@1 632 Class osfClass = com.sun.corba.se.impl.orbutil.ObjectStreamField.class;
duke@1 633
duke@1 634 translation = (Object[])java.lang.reflect.Array.newInstance(osfClass, objs.length);
duke@1 635 Object arg[] = new Object[2];
duke@1 636 Class types[] = {String.class, Class.class};
duke@1 637 Constructor constructor = osfClass.getDeclaredConstructor(types);
duke@1 638 for (int i = fields.length -1; i >= 0; i--){
duke@1 639 arg[0] = fields[i].getName();
duke@1 640 arg[1] = fields[i].getType();
duke@1 641
duke@1 642 translation[i] = constructor.newInstance(arg);
duke@1 643 }
duke@1 644 translatedFields.put(fields, translation);
duke@1 645
duke@1 646 }
duke@1 647
duke@1 648 return (Object[])translation;
duke@1 649 }
duke@1 650 catch(Throwable t){
duke@1 651 throw new NoSuchFieldException();
duke@1 652 }
duke@1 653 }
duke@1 654
duke@1 655 /* Compare the base class names of streamName and localName.
duke@1 656 *
duke@1 657 * @return Return true iff the base class name compare.
duke@1 658 * @parameter streamName Fully qualified class name.
duke@1 659 * @parameter localName Fully qualified class name.
duke@1 660 * @parameter pkgSeparator class names use either '.' or '/'.
duke@1 661 *
duke@1 662 * Only compare base class name to allow package renaming.
duke@1 663 */
duke@1 664 static boolean compareClassNames(String streamName,
duke@1 665 String localName,
duke@1 666 char pkgSeparator) {
duke@1 667 /* compare the class names, stripping off package names. */
duke@1 668 int streamNameIndex = streamName.lastIndexOf(pkgSeparator);
duke@1 669 if (streamNameIndex < 0)
duke@1 670 streamNameIndex = 0;
duke@1 671
duke@1 672 int localNameIndex = localName.lastIndexOf(pkgSeparator);
duke@1 673 if (localNameIndex < 0)
duke@1 674 localNameIndex = 0;
duke@1 675
duke@1 676 return streamName.regionMatches(false, streamNameIndex,
duke@1 677 localName, localNameIndex,
duke@1 678 streamName.length() - streamNameIndex);
duke@1 679 }
duke@1 680
duke@1 681 /*
duke@1 682 * Compare the types of two class descriptors.
duke@1 683 * They match if they have the same class name and suid
duke@1 684 */
duke@1 685 final boolean typeEquals(ObjectStreamClass_1_3_1 other) {
duke@1 686 return (suid == other.suid) &&
duke@1 687 compareClassNames(name, other.name, '.');
duke@1 688 }
duke@1 689
duke@1 690 /*
duke@1 691 * Return the superclass descriptor of this descriptor.
duke@1 692 */
duke@1 693 final void setSuperclass(ObjectStreamClass_1_3_1 s) {
duke@1 694 superclass = s;
duke@1 695 }
duke@1 696
duke@1 697 /*
duke@1 698 * Return the superclass descriptor of this descriptor.
duke@1 699 */
duke@1 700 final ObjectStreamClass_1_3_1 getSuperclass() {
duke@1 701 return superclass;
duke@1 702 }
duke@1 703
duke@1 704 /*
duke@1 705 * Return whether the class has a writeObject method
duke@1 706 */
duke@1 707 final boolean hasWriteObject() {
duke@1 708 return hasWriteObjectMethod;
duke@1 709 }
duke@1 710
duke@1 711 final boolean isCustomMarshaled() {
duke@1 712 return (hasWriteObject() || isExternalizable());
duke@1 713 }
duke@1 714
duke@1 715 /*
duke@1 716 * Return true if all instances of 'this' Externalizable class
duke@1 717 * are written in block-data mode from the stream that 'this' was read
duke@1 718 * from. <p>
duke@1 719 *
duke@1 720 * In JDK 1.1, all Externalizable instances are not written
duke@1 721 * in block-data mode.
duke@1 722 * In JDK 1.2, all Externalizable instances, by default, are written
duke@1 723 * in block-data mode and the Externalizable instance is terminated with
duke@1 724 * tag TC_ENDBLOCKDATA. Change enabled the ability to skip Externalizable
duke@1 725 * instances.
duke@1 726 *
duke@1 727 * IMPLEMENTATION NOTE:
duke@1 728 * This should have been a mode maintained per stream; however,
duke@1 729 * for compatibility reasons, it was only possible to record
duke@1 730 * this change per class. All Externalizable classes within
duke@1 731 * a given stream should either have this mode enabled or
duke@1 732 * disabled. This is enforced by not allowing the PROTOCOL_VERSION
duke@1 733 * of a stream to he changed after any objects have been written.
duke@1 734 *
duke@1 735 * @see ObjectOutputStream#useProtocolVersion
duke@1 736 * @see ObjectStreamConstants#PROTOCOL_VERSION_1
duke@1 737 * @see ObjectStreamConstants#PROTOCOL_VERSION_2
duke@1 738 *
duke@1 739 * @since JDK 1.2
duke@1 740 */
duke@1 741 boolean hasExternalizableBlockDataMode() {
duke@1 742 return hasExternalizableBlockData;
duke@1 743 }
duke@1 744
duke@1 745 /*
duke@1 746 * Return the ObjectStreamClass_1_3_1 of the local class this one is based on.
duke@1 747 */
duke@1 748 final ObjectStreamClass_1_3_1 localClassDescriptor() {
duke@1 749 return localClassDesc;
duke@1 750 }
duke@1 751
duke@1 752 /*
duke@1 753 * Get the Serializability of the class.
duke@1 754 */
duke@1 755 boolean isSerializable() {
duke@1 756 return serializable;
duke@1 757 }
duke@1 758
duke@1 759 /*
duke@1 760 * Get the externalizability of the class.
duke@1 761 */
duke@1 762 boolean isExternalizable() {
duke@1 763 return externalizable;
duke@1 764 }
duke@1 765
duke@1 766 boolean isNonSerializable() {
duke@1 767 return ! (externalizable || serializable);
duke@1 768 }
duke@1 769
duke@1 770 /*
duke@1 771 * Calculate the size of the array needed to store primitive data and the
duke@1 772 * number of object references to read when reading from the input
duke@1 773 * stream.
duke@1 774 */
duke@1 775 private void computeFieldInfo() {
duke@1 776 primBytes = 0;
duke@1 777 objFields = 0;
duke@1 778
duke@1 779 for (int i = 0; i < fields.length; i++ ) {
duke@1 780 switch (fields[i].getTypeCode()) {
duke@1 781 case 'B':
duke@1 782 case 'Z':
duke@1 783 primBytes += 1;
duke@1 784 break;
duke@1 785 case 'C':
duke@1 786 case 'S':
duke@1 787 primBytes += 2;
duke@1 788 break;
duke@1 789
duke@1 790 case 'I':
duke@1 791 case 'F':
duke@1 792 primBytes += 4;
duke@1 793 break;
duke@1 794 case 'J':
duke@1 795 case 'D' :
duke@1 796 primBytes += 8;
duke@1 797 break;
duke@1 798
duke@1 799 case 'L':
duke@1 800 case '[':
duke@1 801 objFields += 1;
duke@1 802 break;
duke@1 803 }
duke@1 804 }
duke@1 805 }
duke@1 806
duke@1 807 private static long computeStructuralUID(ObjectStreamClass_1_3_1 osc, Class cl) {
duke@1 808 ByteArrayOutputStream devnull = new ByteArrayOutputStream(512);
duke@1 809
duke@1 810 long h = 0;
duke@1 811 try {
duke@1 812
duke@1 813 if ((!java.io.Serializable.class.isAssignableFrom(cl)) ||
duke@1 814 (cl.isInterface())){
duke@1 815 return 0;
duke@1 816 }
duke@1 817
duke@1 818 if (java.io.Externalizable.class.isAssignableFrom(cl)) {
duke@1 819 return 1;
duke@1 820 }
duke@1 821
duke@1 822 MessageDigest md = MessageDigest.getInstance("SHA");
duke@1 823 DigestOutputStream mdo = new DigestOutputStream(devnull, md);
duke@1 824 DataOutputStream data = new DataOutputStream(mdo);
duke@1 825
duke@1 826 // Get SUID of parent
duke@1 827 Class parent = cl.getSuperclass();
duke@1 828 if ((parent != null))
duke@1 829 // SerialBug 1; acc. to spec the one for
duke@1 830 // java.lang.object
duke@1 831 // should be computed and put
duke@1 832 // && (parent != java.lang.Object.class))
duke@1 833 {
duke@1 834 //data.writeLong(computeSerialVersionUID(null,parent));
duke@1 835 data.writeLong(computeStructuralUID(lookup(parent), parent));
duke@1 836 }
duke@1 837
duke@1 838 if (osc.hasWriteObject())
duke@1 839 data.writeInt(2);
duke@1 840 else
duke@1 841 data.writeInt(1);
duke@1 842
duke@1 843 /* Sort the field names to get a deterministic order */
duke@1 844 // Field[] field = ObjectStreamClass_1_3_1.getDeclaredFields(cl);
duke@1 845
duke@1 846 ObjectStreamField[] fields = osc.getFields();
duke@1 847
duke@1 848 // Must make sure that the Field array we allocate
duke@1 849 // below is exactly the right size. Bug fix for
duke@1 850 // 4397133.
duke@1 851 int numNonNullFields = 0;
duke@1 852 for (int i = 0; i < fields.length; i++)
duke@1 853 if (fields[i].getField() != null)
duke@1 854 numNonNullFields++;
duke@1 855
duke@1 856 Field [] field = new java.lang.reflect.Field[numNonNullFields];
duke@1 857 for (int i = 0, fieldNum = 0; i < fields.length; i++) {
duke@1 858 if (fields[i].getField() != null) {
duke@1 859 field[fieldNum++] = fields[i].getField();
duke@1 860 }
duke@1 861 }
duke@1 862
duke@1 863 if (field.length > 1)
duke@1 864 Arrays.sort(field, compareMemberByName);
duke@1 865
duke@1 866 for (int i = 0; i < field.length; i++) {
duke@1 867 Field f = field[i];
duke@1 868
duke@1 869 /* Include in the hash all fields except those that are
duke@1 870 * transient
duke@1 871 */
duke@1 872 int m = f.getModifiers();
duke@1 873 //Serial 6
duke@1 874 //if (Modifier.isTransient(m) || Modifier.isStatic(m))
duke@1 875 // spec reference 00-01-06.pdf, 1.3.5.6, states non-static
duke@1 876 // non-transient, public fields are mapped to Java IDL.
duke@1 877 //
duke@1 878 // Here's the quote from the first paragraph:
duke@1 879 // Java non-static non-transient public fields are mapped to
duke@1 880 // OMG IDL public data members, and other Java fields are
duke@1 881 // not mapped.
duke@1 882
duke@1 883 // if (Modifier.isTransient(m) || Modifier.isStatic(m))
duke@1 884 // continue;
duke@1 885
duke@1 886 data.writeUTF(f.getName());
duke@1 887 data.writeUTF(getSignature(f.getType()));
duke@1 888 }
duke@1 889
duke@1 890 /* Compute the hash value for this class.
duke@1 891 * Use only the first 64 bits of the hash.
duke@1 892 */
duke@1 893 data.flush();
duke@1 894 byte hasharray[] = md.digest();
duke@1 895 // int minimum = Math.min(8, hasharray.length);
duke@1 896 // SerialBug 3: SHA computation is wrong; for loop reversed
duke@1 897 //for (int i = minimum; i > 0; i--)
duke@1 898 for (int i = 0; i < Math.min(8, hasharray.length); i++) {
duke@1 899 h += (long)(hasharray[i] & 255) << (i * 8);
duke@1 900 }
duke@1 901 } catch (IOException ignore) {
duke@1 902 /* can't happen, but be deterministic anyway. */
duke@1 903 h = -1;
duke@1 904 } catch (NoSuchAlgorithmException complain) {
duke@1 905 throw new SecurityException(complain.getMessage());
duke@1 906 }
duke@1 907 return h;
duke@1 908 }
duke@1 909
duke@1 910 /**
duke@1 911 * Compute the JVM signature for the class.
duke@1 912 */
duke@1 913 static String getSignature(Class clazz) {
duke@1 914 String type = null;
duke@1 915 if (clazz.isArray()) {
duke@1 916 Class cl = clazz;
duke@1 917 int dimensions = 0;
duke@1 918 while (cl.isArray()) {
duke@1 919 dimensions++;
duke@1 920 cl = cl.getComponentType();
duke@1 921 }
duke@1 922 StringBuffer sb = new StringBuffer();
duke@1 923 for (int i = 0; i < dimensions; i++) {
duke@1 924 sb.append("[");
duke@1 925 }
duke@1 926 sb.append(getSignature(cl));
duke@1 927 type = sb.toString();
duke@1 928 } else if (clazz.isPrimitive()) {
duke@1 929 if (clazz == Integer.TYPE) {
duke@1 930 type = "I";
duke@1 931 } else if (clazz == Byte.TYPE) {
duke@1 932 type = "B";
duke@1 933 } else if (clazz == Long.TYPE) {
duke@1 934 type = "J";
duke@1 935 } else if (clazz == Float.TYPE) {
duke@1 936 type = "F";
duke@1 937 } else if (clazz == Double.TYPE) {
duke@1 938 type = "D";
duke@1 939 } else if (clazz == Short.TYPE) {
duke@1 940 type = "S";
duke@1 941 } else if (clazz == Character.TYPE) {
duke@1 942 type = "C";
duke@1 943 } else if (clazz == Boolean.TYPE) {
duke@1 944 type = "Z";
duke@1 945 } else if (clazz == Void.TYPE) {
duke@1 946 type = "V";
duke@1 947 }
duke@1 948 } else {
duke@1 949 type = "L" + clazz.getName().replace('.', '/') + ";";
duke@1 950 }
duke@1 951 return type;
duke@1 952 }
duke@1 953
duke@1 954 /*
duke@1 955 * Compute the JVM method descriptor for the method.
duke@1 956 */
duke@1 957 static String getSignature(Method meth) {
duke@1 958 StringBuffer sb = new StringBuffer();
duke@1 959
duke@1 960 sb.append("(");
duke@1 961
duke@1 962 Class[] params = meth.getParameterTypes(); // avoid clone
duke@1 963 for (int j = 0; j < params.length; j++) {
duke@1 964 sb.append(getSignature(params[j]));
duke@1 965 }
duke@1 966 sb.append(")");
duke@1 967 sb.append(getSignature(meth.getReturnType()));
duke@1 968 return sb.toString();
duke@1 969 }
duke@1 970
duke@1 971 /*
duke@1 972 * Compute the JVM constructor descriptor for the constructor.
duke@1 973 */
duke@1 974 static String getSignature(Constructor cons) {
duke@1 975 StringBuffer sb = new StringBuffer();
duke@1 976
duke@1 977 sb.append("(");
duke@1 978
duke@1 979 Class[] params = cons.getParameterTypes(); // avoid clone
duke@1 980 for (int j = 0; j < params.length; j++) {
duke@1 981 sb.append(getSignature(params[j]));
duke@1 982 }
duke@1 983 sb.append(")V");
duke@1 984 return sb.toString();
duke@1 985 }
duke@1 986
duke@1 987 /*
duke@1 988 * Cache of Class -> ClassDescriptor Mappings.
duke@1 989 */
duke@1 990 static private ObjectStreamClassEntry[] descriptorFor = new ObjectStreamClassEntry[61];
duke@1 991
duke@1 992 /*
duke@1 993 * findDescriptorFor a Class. This looks in the cache for a
duke@1 994 * mapping from Class -> ObjectStreamClass mappings. The hashCode
duke@1 995 * of the Class is used for the lookup since the Class is the key.
duke@1 996 * The entries are extended from java.lang.ref.SoftReference so the
duke@1 997 * gc will be able to free them if needed.
duke@1 998 */
duke@1 999 private static ObjectStreamClass_1_3_1 findDescriptorFor(Class cl) {
duke@1 1000
duke@1 1001 int hash = cl.hashCode();
duke@1 1002 int index = (hash & 0x7FFFFFFF) % descriptorFor.length;
duke@1 1003 ObjectStreamClassEntry e;
duke@1 1004 ObjectStreamClassEntry prev;
duke@1 1005
duke@1 1006 /* Free any initial entries whose refs have been cleared */
duke@1 1007 while ((e = descriptorFor[index]) != null && e.get() == null) {
duke@1 1008 descriptorFor[index] = e.next;
duke@1 1009 }
duke@1 1010
duke@1 1011 /* Traverse the chain looking for a descriptor with ofClass == cl.
duke@1 1012 * unlink entries that are unresolved.
duke@1 1013 */
duke@1 1014 prev = e;
duke@1 1015 while (e != null ) {
duke@1 1016 ObjectStreamClass_1_3_1 desc = (ObjectStreamClass_1_3_1)(e.get());
duke@1 1017 if (desc == null) {
duke@1 1018 // This entry has been cleared, unlink it
duke@1 1019 prev.next = e.next;
duke@1 1020 } else {
duke@1 1021 if (desc.ofClass == cl)
duke@1 1022 return desc;
duke@1 1023 prev = e;
duke@1 1024 }
duke@1 1025 e = e.next;
duke@1 1026 }
duke@1 1027 return null;
duke@1 1028 }
duke@1 1029
duke@1 1030 /*
duke@1 1031 * insertDescriptorFor a Class -> ObjectStreamClass_1_3_1 mapping.
duke@1 1032 */
duke@1 1033 private static void insertDescriptorFor(ObjectStreamClass_1_3_1 desc) {
duke@1 1034 // Make sure not already present
duke@1 1035 if (findDescriptorFor(desc.ofClass) != null) {
duke@1 1036 return;
duke@1 1037 }
duke@1 1038
duke@1 1039 int hash = desc.ofClass.hashCode();
duke@1 1040 int index = (hash & 0x7FFFFFFF) % descriptorFor.length;
duke@1 1041 ObjectStreamClassEntry e = new ObjectStreamClassEntry(desc);
duke@1 1042 e.next = descriptorFor[index];
duke@1 1043 descriptorFor[index] = e;
duke@1 1044 }
duke@1 1045
duke@1 1046 private static Field[] getDeclaredFields(final Class clz) {
duke@1 1047 return (Field[]) AccessController.doPrivileged(new PrivilegedAction() {
duke@1 1048 public Object run() {
duke@1 1049 return clz.getDeclaredFields();
duke@1 1050 }
duke@1 1051 });
duke@1 1052 }
duke@1 1053
duke@1 1054
duke@1 1055 /*
duke@1 1056 * The name of this descriptor
duke@1 1057 */
duke@1 1058 private String name;
duke@1 1059
duke@1 1060 /*
duke@1 1061 * The descriptor of the supertype.
duke@1 1062 */
duke@1 1063 private ObjectStreamClass_1_3_1 superclass;
duke@1 1064
duke@1 1065 /*
duke@1 1066 * Flags for Serializable and Externalizable.
duke@1 1067 */
duke@1 1068 private boolean serializable;
duke@1 1069 private boolean externalizable;
duke@1 1070
duke@1 1071 /*
duke@1 1072 * Array of persistent fields of this class, sorted by
duke@1 1073 * type and name.
duke@1 1074 */
duke@1 1075 private ObjectStreamField[] fields;
duke@1 1076
duke@1 1077 /*
duke@1 1078 * Class that is a descriptor for in this virtual machine.
duke@1 1079 */
duke@1 1080 private Class ofClass;
duke@1 1081
duke@1 1082 /*
duke@1 1083 * True if descriptor for a proxy class.
duke@1 1084 */
duke@1 1085 boolean forProxyClass;
duke@1 1086
duke@1 1087
duke@1 1088 /*
duke@1 1089 * SerialVersionUID for this class.
duke@1 1090 */
duke@1 1091 private long suid = kDefaultUID;
duke@1 1092 private String suidStr = null;
duke@1 1093
duke@1 1094 /*
duke@1 1095 * Actual (computed) SerialVersionUID for this class.
duke@1 1096 */
duke@1 1097 private long actualSuid = kDefaultUID;
duke@1 1098 private String actualSuidStr = null;
duke@1 1099
duke@1 1100 /*
duke@1 1101 * The total number of bytes of primitive fields.
duke@1 1102 * The total number of object fields.
duke@1 1103 */
duke@1 1104 int primBytes;
duke@1 1105 int objFields;
duke@1 1106
duke@1 1107 /* Internal lock object. */
duke@1 1108 private Object lock = new Object();
duke@1 1109
duke@1 1110 /* True if this class has/had a writeObject method */
duke@1 1111 private boolean hasWriteObjectMethod;
duke@1 1112
duke@1 1113 /* In JDK 1.1, external data was not written in block mode.
duke@1 1114 * As of JDK 1.2, external data is written in block data mode. This
duke@1 1115 * flag enables JDK 1.2 to be able to read JDK 1.1 written external data.
duke@1 1116 *
duke@1 1117 * @since JDK 1.2
duke@1 1118 */
duke@1 1119 private boolean hasExternalizableBlockData;
duke@1 1120 Method writeObjectMethod;
duke@1 1121 Method readObjectMethod;
coffeys@446 1122 private transient Method writeReplaceObjectMethod;
coffeys@446 1123 private transient Method readResolveObjectMethod;
duke@1 1124
duke@1 1125 /*
duke@1 1126 * ObjectStreamClass_1_3_1 that this one was built from.
duke@1 1127 */
duke@1 1128 private ObjectStreamClass_1_3_1 localClassDesc;
duke@1 1129
duke@1 1130 /* Get the private static final field for serial version UID */
duke@1 1131 // private static native long getSerialVersionUIDField(Class cl);
duke@1 1132
duke@1 1133 /* The Class Object for java.io.Serializable */
duke@1 1134 private static Class classSerializable = null;
duke@1 1135 private static Class classExternalizable = null;
duke@1 1136
duke@1 1137 /*
duke@1 1138 * Resolve java.io.Serializable at load time.
duke@1 1139 */
duke@1 1140 static {
duke@1 1141 try {
duke@1 1142 classSerializable = Class.forName("java.io.Serializable");
duke@1 1143 classExternalizable = Class.forName("java.io.Externalizable");
duke@1 1144 } catch (Throwable e) {
duke@1 1145 System.err.println("Could not load java.io.Serializable or java.io.Externalizable.");
duke@1 1146 }
duke@1 1147 }
duke@1 1148
duke@1 1149 /** use serialVersionUID from JDK 1.1. for interoperability */
duke@1 1150 private static final long serialVersionUID = -6120832682080437368L;
duke@1 1151
duke@1 1152 /**
duke@1 1153 * Set serialPersistentFields of a Serializable class to this value to
duke@1 1154 * denote that the class has no Serializable fields.
duke@1 1155 */
duke@1 1156 public static final ObjectStreamField[] NO_FIELDS =
duke@1 1157 new ObjectStreamField[0];
duke@1 1158
duke@1 1159 /*
duke@1 1160 * Entries held in the Cache of known ObjectStreamClass_1_3_1 objects.
duke@1 1161 * Entries are chained together with the same hash value (modulo array size).
duke@1 1162 */
duke@1 1163 private static class ObjectStreamClassEntry // extends java.lang.ref.SoftReference
duke@1 1164 {
duke@1 1165 ObjectStreamClassEntry(ObjectStreamClass_1_3_1 c) {
duke@1 1166 //super(c);
duke@1 1167 this.c = c;
duke@1 1168 }
duke@1 1169 ObjectStreamClassEntry next;
duke@1 1170
duke@1 1171 public Object get()
duke@1 1172 {
duke@1 1173 return c;
duke@1 1174 }
duke@1 1175 private ObjectStreamClass_1_3_1 c;
duke@1 1176 }
duke@1 1177
duke@1 1178 /*
duke@1 1179 * Comparator object for Classes and Interfaces
duke@1 1180 */
duke@1 1181 private static Comparator compareClassByName =
duke@1 1182 new CompareClassByName();
duke@1 1183
duke@1 1184 private static class CompareClassByName implements Comparator {
duke@1 1185 public int compare(Object o1, Object o2) {
duke@1 1186 Class c1 = (Class)o1;
duke@1 1187 Class c2 = (Class)o2;
duke@1 1188 return (c1.getName()).compareTo(c2.getName());
duke@1 1189 }
duke@1 1190 }
duke@1 1191
duke@1 1192 /*
duke@1 1193 * Comparator object for Members, Fields, and Methods
duke@1 1194 */
duke@1 1195 private static Comparator compareMemberByName =
duke@1 1196 new CompareMemberByName();
duke@1 1197
duke@1 1198 private static class CompareMemberByName implements Comparator {
duke@1 1199 public int compare(Object o1, Object o2) {
duke@1 1200 String s1 = ((Member)o1).getName();
duke@1 1201 String s2 = ((Member)o2).getName();
duke@1 1202
duke@1 1203 if (o1 instanceof Method) {
duke@1 1204 s1 += getSignature((Method)o1);
duke@1 1205 s2 += getSignature((Method)o2);
duke@1 1206 } else if (o1 instanceof Constructor) {
duke@1 1207 s1 += getSignature((Constructor)o1);
duke@1 1208 s2 += getSignature((Constructor)o2);
duke@1 1209 }
duke@1 1210 return s1.compareTo(s2);
duke@1 1211 }
duke@1 1212 }
duke@1 1213
duke@1 1214 /* It is expensive to recompute a method or constructor signature
duke@1 1215 many times, so compute it only once using this data structure. */
duke@1 1216 private static class MethodSignature implements Comparator {
duke@1 1217 Member member;
duke@1 1218 String signature; // cached parameter signature
duke@1 1219
duke@1 1220 /* Given an array of Method or Constructor members,
duke@1 1221 return a sorted array of the non-private members.*/
duke@1 1222 /* A better implementation would be to implement the returned data
duke@1 1223 structure as an insertion sorted link list.*/
duke@1 1224 static MethodSignature[] removePrivateAndSort(Member[] m) {
duke@1 1225 int numNonPrivate = 0;
duke@1 1226 for (int i = 0; i < m.length; i++) {
duke@1 1227 if (! Modifier.isPrivate(m[i].getModifiers())) {
duke@1 1228 numNonPrivate++;
duke@1 1229 }
duke@1 1230 }
duke@1 1231 MethodSignature[] cm = new MethodSignature[numNonPrivate];
duke@1 1232 int cmi = 0;
duke@1 1233 for (int i = 0; i < m.length; i++) {
duke@1 1234 if (! Modifier.isPrivate(m[i].getModifiers())) {
duke@1 1235 cm[cmi] = new MethodSignature(m[i]);
duke@1 1236 cmi++;
duke@1 1237 }
duke@1 1238 }
duke@1 1239 if (cmi > 0)
duke@1 1240 Arrays.sort(cm, cm[0]);
duke@1 1241 return cm;
duke@1 1242 }
duke@1 1243
duke@1 1244 /* Assumes that o1 and o2 are either both methods
duke@1 1245 or both constructors.*/
duke@1 1246 public int compare(Object o1, Object o2) {
duke@1 1247 /* Arrays.sort calls compare when o1 and o2 are equal.*/
duke@1 1248 if (o1 == o2)
duke@1 1249 return 0;
duke@1 1250
duke@1 1251 MethodSignature c1 = (MethodSignature)o1;
duke@1 1252 MethodSignature c2 = (MethodSignature)o2;
duke@1 1253
duke@1 1254 int result;
duke@1 1255 if (isConstructor()) {
duke@1 1256 result = c1.signature.compareTo(c2.signature);
duke@1 1257 } else { // is a Method.
duke@1 1258 result = c1.member.getName().compareTo(c2.member.getName());
duke@1 1259 if (result == 0)
duke@1 1260 result = c1.signature.compareTo(c2.signature);
duke@1 1261 }
duke@1 1262 return result;
duke@1 1263 }
duke@1 1264
duke@1 1265 final private boolean isConstructor() {
duke@1 1266 return member instanceof Constructor;
duke@1 1267 }
duke@1 1268 private MethodSignature(Member m) {
duke@1 1269 member = m;
duke@1 1270 if (isConstructor()) {
duke@1 1271 signature = ObjectStreamClass_1_3_1.getSignature((Constructor)m);
duke@1 1272 } else {
duke@1 1273 signature = ObjectStreamClass_1_3_1.getSignature((Method)m);
duke@1 1274 }
duke@1 1275 }
duke@1 1276 }
duke@1 1277 }

mercurial