Overview Package Class Use Source Tree Index Deprecated About
GNU Classpath (0.95)
Frames | No Frames

Source for java.io.ObjectStreamClass

 1:  /* ObjectStreamClass.java -- Class used to write class information
 2:  about serialized objects.
 3:  Copyright (C) 1998, 1999, 2000, 2001, 2003, 2005 Free Software Foundation, Inc.
 4: 
 5: This file is part of GNU Classpath.
 6: 
 7: GNU Classpath is free software; you can redistribute it and/or modify
 8: it under the terms of the GNU General Public License as published by
 9: the Free Software Foundation; either version 2, or (at your option)
 10: any later version.
 11:  
 12: GNU Classpath is distributed in the hope that it will be useful, but
 13: WITHOUT ANY WARRANTY; without even the implied warranty of
 14: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 15: General Public License for more details.
 16: 
 17: You should have received a copy of the GNU General Public License
 18: along with GNU Classpath; see the file COPYING. If not, write to the
 19: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 20: 02110-1301 USA.
 21: 
 22: Linking this library statically or dynamically with other modules is
 23: making a combined work based on this library. Thus, the terms and
 24: conditions of the GNU General Public License cover the whole
 25: combination.
 26: 
 27: As a special exception, the copyright holders of this library give you
 28: permission to link this library with independent modules to produce an
 29: executable, regardless of the license terms of these independent
 30: modules, and to copy and distribute the resulting executable under
 31: terms of your choice, provided that you also meet, for each linked
 32: independent module, the terms and conditions of the license of that
 33: module. An independent module is a module which is not derived from
 34: or based on this library. If you modify this library, you may extend
 35: this exception to your version of the library, but you are not
 36: obligated to do so. If you do not wish to do so, delete this
 37: exception statement from your version. */
 38: 
 39: 
 40:  package java.io;
 41: 
 42:  import gnu.java.io.NullOutputStream;
 43:  import gnu.java.lang.reflect.TypeSignature;
 44:  import gnu.java.security.action.SetAccessibleAction;
 45:  import gnu.java.security.provider.Gnu;
 46: 
 47:  import java.lang.reflect.Constructor;
 48:  import java.lang.reflect.Field;
 49:  import java.lang.reflect.Member;
 50:  import java.lang.reflect.Method;
 51:  import java.lang.reflect.Modifier;
 52:  import java.lang.reflect.Proxy;
 53:  import java.security.AccessController;
 54:  import java.security.DigestOutputStream;
 55:  import java.security.MessageDigest;
 56:  import java.security.NoSuchAlgorithmException;
 57:  import java.security.PrivilegedAction;
 58:  import java.security.Security;
 59:  import java.util.Arrays;
 60:  import java.util.Comparator;
 61:  import java.util.Hashtable;
 62: 
 63:  /**
 64:  * @author Tom Tromey (tromey@redhat.com)
 65:  * @author Jeroen Frijters (jeroen@frijters.net)
 66:  * @author Guilhem Lavaux (guilhem@kaffe.org)
 67:  * @author Michael Koch (konqueror@gmx.de)
 68:  * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
 69:  */
 70:  public class ObjectStreamClass implements Serializable
 71: {
 72:  static final ObjectStreamField[] INVALID_FIELDS = new ObjectStreamField[0];
 73: 
 74:  /**
 75:  * Returns the <code>ObjectStreamClass</code> for <code>cl</code>.
 76:  * If <code>cl</code> is null, or is not <code>Serializable</code>,
 77:  * null is returned. <code>ObjectStreamClass</code>'s are memorized;
 78:  * later calls to this method with the same class will return the
 79:  * same <code>ObjectStreamClass</code> object and no recalculation
 80:  * will be done.
 81:  *
 82:  * Warning: If this class contains an invalid serialPersistentField arrays
 83:  * lookup will not throw anything. However {@link #getFields()} will return
 84:  * an empty array and {@link java.io.ObjectOutputStream#writeObject} will throw an 
 85:  * {@link java.io.InvalidClassException}.
 86:  *
 87:  * @see java.io.Serializable
 88:  */
 89:  public static ObjectStreamClass lookup(Class<?> cl)
 90:  {
 91:  if (cl == null)
 92:  return null;
 93:  if (! (Serializable.class).isAssignableFrom(cl))
 94:  return null;
 95: 
 96:  return lookupForClassObject(cl);
 97:  }
 98: 
 99:  /**
 100:  * This lookup for internal use by ObjectOutputStream. Suppose
 101:  * we have a java.lang.Class object C for class A, though A is not
 102:  * serializable, but it's okay to serialize C.
 103:  */
 104:  static ObjectStreamClass lookupForClassObject(Class cl)
 105:  {
 106:  if (cl == null)
 107:  return null;
 108: 
 109:  ObjectStreamClass osc = (ObjectStreamClass) classLookupTable.get(cl);
 110: 
 111:  if (osc != null)
 112:  return osc;
 113:  else
 114:  {
 115:  osc = new ObjectStreamClass(cl);
 116:  classLookupTable.put(cl, osc);
 117:  return osc;
 118:  }
 119:  }
 120: 
 121:  /**
 122:  * Returns the name of the class that this
 123:  * <code>ObjectStreamClass</code> represents.
 124:  *
 125:  * @return the name of the class.
 126:  */
 127:  public String getName()
 128:  {
 129:  return name;
 130:  }
 131: 
 132:  /**
 133:  * Returns the class that this <code>ObjectStreamClass</code>
 134:  * represents. Null could be returned if this
 135:  * <code>ObjectStreamClass</code> was read from an
 136:  * <code>ObjectInputStream</code> and the class it represents cannot
 137:  * be found or loaded.
 138:  *
 139:  * @see java.io.ObjectInputStream
 140:  */
 141:  public Class<?> forClass()
 142:  {
 143:  return clazz;
 144:  }
 145: 
 146:  /**
 147:  * Returns the serial version stream-unique identifier for the class
 148:  * represented by this <code>ObjectStreamClass</code>. This SUID is
 149:  * either defined by the class as <code>static final long
 150:  * serialVersionUID</code> or is calculated as specified in
 151:  * Javasoft's "Object Serialization Specification" XXX: add reference
 152:  *
 153:  * @return the serial version UID.
 154:  */
 155:  public long getSerialVersionUID()
 156:  {
 157:  return uid;
 158:  }
 159: 
 160:  /**
 161:  * Returns the serializable (non-static and non-transient) Fields
 162:  * of the class represented by this ObjectStreamClass. The Fields
 163:  * are sorted by name.
 164:  * If fields were obtained using serialPersistentFields and this array
 165:  * is faulty then the returned array of this method will be empty.
 166:  *
 167:  * @return the fields.
 168:  */
 169:  public ObjectStreamField[] getFields()
 170:  {
 171:  ObjectStreamField[] copy = new ObjectStreamField[ fields.length ];
 172:  System.arraycopy(fields, 0, copy, 0, fields.length);
 173:  return copy;
 174:  }
 175: 
 176:  // XXX doc
 177:  // Can't do binary search since fields is sorted by name and
 178:  // primitiveness.
 179:  public ObjectStreamField getField (String name)
 180:  {
 181:  for (int i = 0; i < fields.length; i++)
 182:  if (fields[i].getName().equals(name))
 183:  return fields[i];
 184:  return null;
 185:  }
 186: 
 187:  /**
 188:  * Returns a textual representation of this
 189:  * <code>ObjectStreamClass</code> object including the name of the
 190:  * class it represents as well as that class's serial version
 191:  * stream-unique identifier.
 192:  *
 193:  * @see #getSerialVersionUID()
 194:  * @see #getName()
 195:  */
 196:  public String toString()
 197:  {
 198:  return "java.io.ObjectStreamClass< " + name + ", " + uid + " >";
 199:  }
 200: 
 201:  // Returns true iff the class that this ObjectStreamClass represents
 202:  // has the following method:
 203:  //
 204:  // private void writeObject (ObjectOutputStream)
 205:  //
 206:  // This method is used by the class to override default
 207:  // serialization behavior.
 208:  boolean hasWriteMethod()
 209:  {
 210:  return (flags & ObjectStreamConstants.SC_WRITE_METHOD) != 0;
 211:  }
 212: 
 213:  // Returns true iff the class that this ObjectStreamClass represents
 214:  // implements Serializable but does *not* implement Externalizable.
 215:  boolean isSerializable()
 216:  {
 217:  return (flags & ObjectStreamConstants.SC_SERIALIZABLE) != 0;
 218:  }
 219: 
 220: 
 221:  // Returns true iff the class that this ObjectStreamClass represents
 222:  // implements Externalizable.
 223:  boolean isExternalizable()
 224:  {
 225:  return (flags & ObjectStreamConstants.SC_EXTERNALIZABLE) != 0;
 226:  }
 227: 
 228:  // Returns true iff the class that this ObjectStreamClass represents
 229:  // implements Externalizable.
 230:  boolean isEnum()
 231:  {
 232:  return (flags & ObjectStreamConstants.SC_ENUM) != 0;
 233:  }
 234: 
 235:  // Returns the <code>ObjectStreamClass</code> that represents the
 236:  // class that is the superclass of the class this
 237:  // <code>ObjectStreamClass</code> represents. If the superclass is
 238:  // not Serializable, null is returned.
 239:  ObjectStreamClass getSuper()
 240:  {
 241:  return superClass;
 242:  }
 243: 
 244:  /**
 245:  * returns an array of ObjectStreamClasses that represent the super
 246:  * classes of the class represented by this and the class
 247:  * represented by this itself in order from most super to this.
 248:  * ObjectStreamClass[0] is the highest superclass of this that is
 249:  * serializable.
 250:  *
 251:  * The result of consecutive calls this hierarchy() will be the same
 252:  * array instance.
 253:  *
 254:  * @return an array of ObjectStreamClass representing the
 255:  * super-class hierarchy of serializable classes.
 256:  */
 257:  ObjectStreamClass[] hierarchy()
 258:  {
 259:  ObjectStreamClass[] result = hierarchy; 
 260:  if (result == null)
 261:  {
 262:  int d = 0; 
 263:  
 264:  for(ObjectStreamClass osc = this; osc != null; osc = osc.getSuper())
 265:  d++;
 266:  
 267:  result = new ObjectStreamClass[d];
 268:  
 269:  for (ObjectStreamClass osc = this; osc != null; osc = osc.getSuper())
 270:  {
 271:  result[--d] = osc;
 272:  }
 273:  
 274:  hierarchy = result; 
 275:  }
 276:  return result; 
 277:  }
 278: 
 279:  /**
 280:  * Cache for hierarchy() result.
 281:  */
 282:  private ObjectStreamClass[] hierarchy = null;
 283: 
 284:  // Returns an integer that consists of bit-flags that indicate
 285:  // properties of the class represented by this ObjectStreamClass.
 286:  // The bit-flags that could be present are those defined in
 287:  // ObjectStreamConstants that begin with `SC_'
 288:  int getFlags()
 289:  {
 290:  return flags;
 291:  }
 292: 
 293: 
 294:  ObjectStreamClass(String name, long uid, byte flags,
 295:  ObjectStreamField[] fields)
 296:  {
 297:  this.name = name;
 298:  this.uid = uid;
 299:  this.flags = flags;
 300:  this.fields = fields;
 301:  }
 302: 
 303:  /**
 304:  * This method builds the internal description corresponding to a Java Class.
 305:  * As the constructor only assign a name to the current ObjectStreamClass instance,
 306:  * that method sets the serial UID, chose the fields which will be serialized,
 307:  * and compute the position of the fields in the serialized stream.
 308:  *
 309:  * @param cl The Java class which is used as a reference for building the descriptor.
 310:  * @param superClass The descriptor of the super class for this class descriptor.
 311:  * @throws InvalidClassException if an incompatibility between computed UID and
 312:  * already set UID is found.
 313:  */
 314:  void setClass(Class cl, ObjectStreamClass superClass) throws InvalidClassException
 315:  {hierarchy = null;
 316:  this.clazz = cl;
 317: 
 318:  cacheMethods();
 319: 
 320:  long class_uid = getClassUID(cl);
 321:  if (uid == 0)
 322:  uid = class_uid;
 323:  else
 324:  {
 325:  // Check that the actual UID of the resolved class matches the UID from 
 326:  // the stream. Mismatches for array classes are ignored.
 327:  if (!cl.isArray() && uid != class_uid)
 328:  {
 329:  String msg = cl + 
 330:  ": Local class not compatible: stream serialVersionUID="
 331:  + uid + ", local serialVersionUID=" + class_uid;
 332:  throw new InvalidClassException (msg);
 333:  }
 334:  }
 335: 
 336:  isProxyClass = clazz != null && Proxy.isProxyClass(clazz);
 337:  this.superClass = superClass;
 338:  calculateOffsets();
 339:  
 340:  try
 341:  {
 342:  ObjectStreamField[] exportedFields = getSerialPersistentFields (clazz); 
 343: 
 344:  if (exportedFields == null)
 345:  return;
 346: 
 347:  ObjectStreamField[] newFieldList = new ObjectStreamField[exportedFields.length + fields.length];
 348:  int i, j, k;
 349: 
 350:  /* We now check the import fields against the exported fields.
 351:  * There should not be contradiction (e.g. int x and String x)
 352:  * but extra virtual fields can be added to the class.
 353:  */
 354: 
 355:  Arrays.sort(exportedFields);
 356: 
 357:  i = 0; j = 0; k = 0;
 358:  while (i < fields.length && j < exportedFields.length)
 359:  {
 360:  int comp = fields[i].compareTo(exportedFields[j]);
 361: 
 362:  if (comp < 0)
 363:  {
 364:  newFieldList[k] = fields[i];
 365:  fields[i].setPersistent(false);
 366:  fields[i].setToSet(false);
 367:  i++;
 368:  }
 369:  else if (comp > 0)
 370:  {
 371:  /* field not found in imported fields. We add it
 372:  * in the list of supported fields.
 373:  */
 374:  newFieldList[k] = exportedFields[j];
 375:  newFieldList[k].setPersistent(true);
 376:  newFieldList[k].setToSet(false);
 377:  try
 378:  {
 379:  newFieldList[k].lookupField(clazz);
 380:  newFieldList[k].checkFieldType();
 381:  }
 382:  catch (NoSuchFieldException _)
 383:  {
 384:  }
 385:  j++;
 386:  }
 387:  else
 388:  {
 389:  try
 390:  {
 391:  exportedFields[j].lookupField(clazz);
 392:  exportedFields[j].checkFieldType();
 393:  }
 394:  catch (NoSuchFieldException _)
 395:  {
 396:  }
 397: 
 398:  if (!fields[i].getType().equals(exportedFields[j].getType()))
 399:  throw new InvalidClassException
 400:  ("serialPersistentFields must be compatible with" +
 401:  " imported fields (about " + fields[i].getName() + ")");
 402:  newFieldList[k] = fields[i];
 403:  fields[i].setPersistent(true);
 404:  i++;
 405:  j++;
 406:  }
 407:  k++;
 408:  }
 409: 
 410:  if (i < fields.length)
 411:  for (;i<fields.length;i++,k++)
 412:  {
 413:  fields[i].setPersistent(false);
 414:  fields[i].setToSet(false);
 415:  newFieldList[k] = fields[i];
 416:  }
 417:  else
 418:  if (j < exportedFields.length)
 419:  for (;j<exportedFields.length;j++,k++)
 420:  {
 421:  exportedFields[j].setPersistent(true);
 422:  exportedFields[j].setToSet(false);
 423:  newFieldList[k] = exportedFields[j];
 424:  }
 425:  
 426:  fields = new ObjectStreamField[k];
 427:  System.arraycopy(newFieldList, 0, fields, 0, k);
 428:  }
 429:  catch (NoSuchFieldException ignore)
 430:  {
 431:  return;
 432:  }
 433:  catch (IllegalAccessException ignore)
 434:  {
 435:  return;
 436:  }
 437:  }
 438: 
 439:  void setSuperclass (ObjectStreamClass osc)
 440:  {
 441:  superClass = osc;
 442:  hierarchy = null;
 443:  }
 444: 
 445:  void calculateOffsets()
 446:  {
 447:  int i;
 448:  ObjectStreamField field;
 449:  primFieldSize = 0;
 450:  int fcount = fields.length;
 451:  for (i = 0; i < fcount; ++ i)
 452:  {
 453:  field = fields[i];
 454: 
 455:  if (! field.isPrimitive())
 456:  break;
 457: 
 458:  field.setOffset(primFieldSize);
 459:  switch (field.getTypeCode())
 460:  {
 461:  case 'B':
 462:  case 'Z':
 463:  ++ primFieldSize;
 464:  break;
 465:  case 'C':
 466:  case 'S':
 467:  primFieldSize += 2;
 468:  break;
 469:  case 'I':
 470:  case 'F':
 471:  primFieldSize += 4;
 472:  break;
 473:  case 'D':
 474:  case 'J':
 475:  primFieldSize += 8;
 476:  break;
 477:  }
 478:  }
 479: 
 480:  for (objectFieldCount = 0; i < fcount; ++ i)
 481:  fields[i].setOffset(objectFieldCount++);
 482:  }
 483: 
 484:  private Method findMethod(Method[] methods, String name, Class[] params,
 485:  Class returnType, boolean mustBePrivate)
 486:  {
 487:  outer:
 488:  for (int i = 0; i < methods.length; i++)
 489:  {
 490:  final Method m = methods[i];
 491:  int mods = m.getModifiers();
 492:  if (Modifier.isStatic(mods)
 493:  || (mustBePrivate && !Modifier.isPrivate(mods)))
 494:  {
 495:  continue;
 496:  }
 497: 
 498:  if (m.getName().equals(name)
 499:  && m.getReturnType() == returnType)
 500:  {
 501:  Class[] mp = m.getParameterTypes();
 502:  if (mp.length == params.length)
 503:  {
 504:  for (int j = 0; j < mp.length; j++)
 505:  {
 506:  if (mp[j] != params[j])
 507:  {
 508:  continue outer;
 509:  }
 510:  }
 511:  AccessController.doPrivileged(new SetAccessibleAction(m));
 512:  return m;
 513:  }
 514:  }
 515:  }
 516:  return null;
 517:  }
 518: 
 519:  private static boolean inSamePackage(Class c1, Class c2)
 520:  {
 521:  String name1 = c1.getName();
 522:  String name2 = c2.getName();
 523: 
 524:  int id1 = name1.lastIndexOf('.');
 525:  int id2 = name2.lastIndexOf('.');
 526: 
 527:  // Handle the default package
 528:  if (id1 == -1 || id2 == -1)
 529:  return id1 == id2;
 530: 
 531:  String package1 = name1.substring(0, id1);
 532:  String package2 = name2.substring(0, id2);
 533: 
 534:  return package1.equals(package2);
 535:  }
 536: 
 537:  final static Class[] noArgs = new Class[0];
 538: 
 539:  private static Method findAccessibleMethod(String name, Class from)
 540:  {
 541:  for (Class c = from; c != null; c = c.getSuperclass())
 542:  {
 543:  try
 544:  {
 545:  Method res = c.getDeclaredMethod(name, noArgs);
 546:  int mods = res.getModifiers();
 547:  
 548:  if (c == from 
 549:  || Modifier.isProtected(mods)
 550:  || Modifier.isPublic(mods)
 551:  || (! Modifier.isPrivate(mods) && inSamePackage(c, from)))
 552:  {
 553:  AccessController.doPrivileged(new SetAccessibleAction(res));
 554:  return res;
 555:  }
 556:  }
 557:  catch (NoSuchMethodException e)
 558:  {
 559:  }
 560:  }
 561: 
 562:  return null;
 563:  }
 564: 
 565:  /**
 566:  * Helper routine to check if a class was loaded by boot or
 567:  * application class loader. Classes for which this is not the case
 568:  * should not be cached since caching prevent class file garbage
 569:  * collection.
 570:  *
 571:  * @param cl a class
 572:  *
 573:  * @return true if cl was loaded by boot or application class loader,
 574:  * false if cl was loaded by a user class loader.
 575:  */
 576:  private static boolean loadedByBootOrApplicationClassLoader(Class cl)
 577:  {
 578:  ClassLoader l = cl.getClassLoader();
 579:  return 
 580:  ( l == null /* boot loader */ ) 
 581:  || (l == ClassLoader.getSystemClassLoader() /* application loader */);
 582:  } 
 583: 
 584:  static Hashtable methodCache = new Hashtable(); 
 585:  
 586:  static final Class[] readObjectSignature = { ObjectInputStream.class };
 587:  static final Class[] writeObjectSignature = { ObjectOutputStream.class };
 588: 
 589:  private void cacheMethods()
 590:  {
 591:  Class cl = forClass(); 
 592:  Method[] cached = (Method[]) methodCache.get(cl); 
 593:  if (cached == null)
 594:  {
 595:  cached = new Method[4];
 596:  Method[] methods = cl.getDeclaredMethods();
 597:  
 598:  cached[0] = findMethod(methods, "readObject",
 599:  readObjectSignature, 
 600:  Void.TYPE, true);
 601:  cached[1] = findMethod(methods, "writeObject",
 602:  writeObjectSignature, 
 603:  Void.TYPE, true);
 604: 
 605:  // readResolve and writeReplace can be in parent classes, as long as they
 606:  // are accessible from this class.
 607:  cached[2] = findAccessibleMethod("readResolve", cl);
 608:  cached[3] = findAccessibleMethod("writeReplace", cl);
 609:  
 610:  /* put in cache if classes not loaded by user class loader.
 611:  * For a user class loader, the cache may otherwise grow
 612:  * without limit.
 613:  */
 614:  if (loadedByBootOrApplicationClassLoader(cl))
 615:  methodCache.put(cl,cached);
 616:  }
 617:  readObjectMethod = cached[0];
 618:  writeObjectMethod = cached[1];
 619:  readResolveMethod = cached[2];
 620:  writeReplaceMethod = cached[3];
 621:  }
 622: 
 623:  private ObjectStreamClass(Class cl)
 624:  {
 625:  uid = 0;
 626:  flags = 0;
 627:  isProxyClass = Proxy.isProxyClass(cl);
 628: 
 629:  clazz = cl;
 630:  cacheMethods();
 631:  name = cl.getName();
 632:  setFlags(cl);
 633:  setFields(cl);
 634:  // to those class nonserializable, its uid field is 0
 635:  if ( (Serializable.class).isAssignableFrom(cl) && !isProxyClass)
 636:  uid = getClassUID(cl);
 637:  superClass = lookup(cl.getSuperclass());
 638:  }
 639: 
 640: 
 641:  // Sets bits in flags according to features of CL.
 642:  private void setFlags(Class cl)
 643:  {
 644:  if ((java.io.Externalizable.class).isAssignableFrom(cl))
 645:  flags |= ObjectStreamConstants.SC_EXTERNALIZABLE;
 646:  else if ((java.io.Serializable.class).isAssignableFrom(cl))
 647:  // only set this bit if CL is NOT Externalizable
 648:  flags |= ObjectStreamConstants.SC_SERIALIZABLE;
 649: 
 650:  if (writeObjectMethod != null)
 651:  flags |= ObjectStreamConstants.SC_WRITE_METHOD;
 652: 
 653:  if (cl.isEnum() || cl == Enum.class)
 654:  flags |= ObjectStreamConstants.SC_ENUM;
 655:  }
 656: 
 657: 
 658:  // Sets fields to be a sorted array of the serializable fields of
 659:  // clazz.
 660:  private void setFields(Class cl)
 661:  {
 662:  SetAccessibleAction setAccessible = new SetAccessibleAction();
 663: 
 664:  if (!isSerializable() || isExternalizable() || isEnum())
 665:  {
 666:  fields = NO_FIELDS;
 667:  return;
 668:  }
 669: 
 670:  try
 671:  {
 672:  final Field f =
 673:  cl.getDeclaredField("serialPersistentFields");
 674:  setAccessible.setMember(f);
 675:  AccessController.doPrivileged(setAccessible);
 676:  int modifiers = f.getModifiers();
 677: 
 678:  if (Modifier.isStatic(modifiers)
 679:  && Modifier.isFinal(modifiers)
 680:  && Modifier.isPrivate(modifiers))
 681:  {
 682:  fields = getSerialPersistentFields(cl);
 683:  if (fields != null)
 684:  {
 685:  ObjectStreamField[] fieldsName = new ObjectStreamField[fields.length];
 686:  System.arraycopy(fields, 0, fieldsName, 0, fields.length);
 687: 
 688:  Arrays.sort (fieldsName, new Comparator() {
 689:  public int compare(Object o1, Object o2)
 690:  {
 691:  ObjectStreamField f1 = (ObjectStreamField)o1;
 692:  ObjectStreamField f2 = (ObjectStreamField)o2;
 693:  
 694:  return f1.getName().compareTo(f2.getName());
 695:  }
 696:  });
 697:  
 698:  for (int i=1; i < fields.length; i++)
 699:  {
 700:  if (fieldsName[i-1].getName().equals(fieldsName[i].getName()))
 701:  {
 702:  fields = INVALID_FIELDS;
 703:  return;
 704:  }
 705:  }
 706: 
 707:  Arrays.sort (fields);
 708:  // Retrieve field reference.
 709:  for (int i=0; i < fields.length; i++)
 710:  {
 711:  try
 712:  {
 713:  fields[i].lookupField(cl);
 714:  }
 715:  catch (NoSuchFieldException _)
 716:  {
 717:  fields[i].setToSet(false);
 718:  }
 719:  }
 720:  
 721:  calculateOffsets();
 722:  return;
 723:  }
 724:  }
 725:  }
 726:  catch (NoSuchFieldException ignore)
 727:  {
 728:  }
 729:  catch (IllegalAccessException ignore)
 730:  {
 731:  }
 732: 
 733:  int num_good_fields = 0;
 734:  Field[] all_fields = cl.getDeclaredFields();
 735: 
 736:  int modifiers;
 737:  // set non-serializable fields to null in all_fields
 738:  for (int i = 0; i < all_fields.length; i++)
 739:  {
 740:  modifiers = all_fields[i].getModifiers();
 741:  if (Modifier.isTransient(modifiers)
 742:  || Modifier.isStatic(modifiers))
 743:  all_fields[i] = null;
 744:  else
 745:  num_good_fields++;
 746:  }
 747: 
 748:  // make a copy of serializable (non-null) fields
 749:  fields = new ObjectStreamField[ num_good_fields ];
 750:  for (int from = 0, to = 0; from < all_fields.length; from++)
 751:  if (all_fields[from] != null)
 752:  {
 753:  final Field f = all_fields[from];
 754:  setAccessible.setMember(f);
 755:  AccessController.doPrivileged(setAccessible);
 756:  fields[to] = new ObjectStreamField(all_fields[from]);
 757:  to++;
 758:  }
 759: 
 760:  Arrays.sort(fields);
 761:  // Make sure we don't have any duplicate field names
 762:  // (Sun JDK 1.4.1. throws an Internal Error as well)
 763:  for (int i = 1; i < fields.length; i++)
 764:  {
 765:  if(fields[i - 1].getName().equals(fields[i].getName()))
 766:  throw new InternalError("Duplicate field " + 
 767:  fields[i].getName() + " in class " + cl.getName());
 768:  }
 769:  calculateOffsets();
 770:  }
 771: 
 772:  static Hashtable uidCache = new Hashtable();
 773: 
 774:  // Returns the serial version UID defined by class, or if that
 775:  // isn't present, calculates value of serial version UID.
 776:  private long getClassUID(Class cl)
 777:  {
 778:  long result = 0;
 779:  Long cache = (Long) uidCache.get(cl);
 780:  if (cache != null)
 781:  result = cache.longValue(); 
 782:  else
 783:  {
 784:  try
 785:  {
 786:  result = getClassUIDFromField(cl);
 787:  }
 788:  catch (NoSuchFieldException ignore)
 789:  {
 790:  try
 791:  {
 792:  result = calculateClassUID(cl);
 793:  }
 794:  catch (NoSuchAlgorithmException e)
 795:  {
 796:  throw new RuntimeException
 797:  ("The SHA algorithm was not found to use in computing the Serial Version UID for class "
 798:  + cl.getName(), e);
 799:  }
 800:  catch (IOException ioe)
 801:  {
 802:  throw new RuntimeException(ioe);
 803:  }
 804:  }
 805: 
 806:  if (loadedByBootOrApplicationClassLoader(cl))
 807:  uidCache.put(cl,new Long(result));
 808:  }
 809:  return result;
 810:  }
 811: 
 812:  /**
 813:  * Search for a serialVersionUID field in the given class and read
 814:  * its value.
 815:  *
 816:  * @return the contents of the serialVersionUID field
 817:  *
 818:  * @throws NoSuchFieldException if such a field does not exist or is
 819:  * not static, not final, not of type Long or not accessible.
 820:  */
 821:  long getClassUIDFromField(Class cl) 
 822:  throws NoSuchFieldException
 823:  {
 824:  long result;
 825:  
 826:  try
 827:  {
 828:  // Use getDeclaredField rather than getField, since serialVersionUID
 829:  // may not be public AND we only want the serialVersionUID of this
 830:  // class, not a superclass or interface.
 831:  final Field suid = cl.getDeclaredField("serialVersionUID");
 832:  SetAccessibleAction setAccessible = new SetAccessibleAction(suid);
 833:  AccessController.doPrivileged(setAccessible);
 834:  int modifiers = suid.getModifiers();
 835:  
 836:  if (Modifier.isStatic(modifiers)
 837:  && Modifier.isFinal(modifiers)
 838:  && suid.getType() == Long.TYPE)
 839:  result = suid.getLong(null);
 840:  else
 841:  throw new NoSuchFieldException();
 842:  }
 843:  catch (IllegalAccessException ignore)
 844:  {
 845:  throw new NoSuchFieldException();
 846:  }
 847: 
 848:  return result;
 849:  }
 850: 
 851:  /**
 852:  * Calculate class serial version UID for a class that does not
 853:  * define serialVersionUID:
 854:  *
 855:  * @param cl a class
 856:  *
 857:  * @return the calculated serial varsion UID.
 858:  *
 859:  * @throws NoSuchAlgorithmException if SHA algorithm not found
 860:  *
 861:  * @throws IOException if writing to the DigestOutputStream causes
 862:  * an IOException.
 863:  */
 864:  long calculateClassUID(Class cl) 
 865:  throws NoSuchAlgorithmException, IOException
 866:  {
 867:  long result; 
 868:  MessageDigest md;
 869:  try 
 870:  {
 871:  md = MessageDigest.getInstance("SHA");
 872:  }
 873:  catch (NoSuchAlgorithmException e)
 874:  {
 875:  // If a provider already provides SHA, use it; otherwise, use this.
 876:  Gnu gnuProvider = new Gnu();
 877:  Security.addProvider(gnuProvider);
 878:  md = MessageDigest.getInstance("SHA");
 879:  }
 880:  
 881:  DigestOutputStream digest_out =
 882:  new DigestOutputStream(nullOutputStream, md);
 883:  DataOutputStream data_out = new DataOutputStream(digest_out);
 884:  
 885:  data_out.writeUTF(cl.getName());
 886:  
 887:  int modifiers = cl.getModifiers();
 888:  // just look at interesting bits
 889:  modifiers = modifiers & (Modifier.ABSTRACT | Modifier.FINAL
 890:  | Modifier.INTERFACE | Modifier.PUBLIC);
 891:  data_out.writeInt(modifiers);
 892:  
 893:  // Pretend that an array has no interfaces, because when array
 894:  // serialization was defined (JDK 1.1), arrays didn't have it.
 895:  if (! cl.isArray())
 896:  {
 897:  Class[] interfaces = cl.getInterfaces();
 898:  Arrays.sort(interfaces, interfaceComparator);
 899:  for (int i = 0; i < interfaces.length; i++)
 900:  data_out.writeUTF(interfaces[i].getName());
 901:  }
 902:  
 903:  Field field;
 904:  Field[] fields = cl.getDeclaredFields();
 905:  Arrays.sort(fields, memberComparator);
 906:  for (int i = 0; i < fields.length; i++)
 907:  {
 908:  field = fields[i];
 909:  modifiers = field.getModifiers();
 910:  if (Modifier.isPrivate(modifiers)
 911:  && (Modifier.isStatic(modifiers)
 912:  || Modifier.isTransient(modifiers)))
 913:  continue;
 914:  
 915:  data_out.writeUTF(field.getName());
 916:  data_out.writeInt(modifiers);
 917:  data_out.writeUTF(TypeSignature.getEncodingOfClass (field.getType()));
 918:  }
 919:  
 920:  // write class initializer method if present
 921:  if (VMObjectStreamClass.hasClassInitializer(cl))
 922:  {
 923:  data_out.writeUTF("<clinit>");
 924:  data_out.writeInt(Modifier.STATIC);
 925:  data_out.writeUTF("()V");
 926:  }
 927:  
 928:  Constructor constructor;
 929:  Constructor[] constructors = cl.getDeclaredConstructors();
 930:  Arrays.sort (constructors, memberComparator);
 931:  for (int i = 0; i < constructors.length; i++)
 932:  {
 933:  constructor = constructors[i];
 934:  modifiers = constructor.getModifiers();
 935:  if (Modifier.isPrivate(modifiers))
 936:  continue;
 937:  
 938:  data_out.writeUTF("<init>");
 939:  data_out.writeInt(modifiers);
 940:  
 941:  // the replacement of '/' with '.' was needed to make computed
 942:  // SUID's agree with those computed by JDK
 943:  data_out.writeUTF 
 944:  (TypeSignature.getEncodingOfConstructor(constructor).replace('/','.'));
 945:  }
 946:  
 947:  Method method;
 948:  Method[] methods = cl.getDeclaredMethods();
 949:  Arrays.sort(methods, memberComparator);
 950:  for (int i = 0; i < methods.length; i++)
 951:  {
 952:  method = methods[i];
 953:  modifiers = method.getModifiers();
 954:  if (Modifier.isPrivate(modifiers))
 955:  continue;
 956:  
 957:  data_out.writeUTF(method.getName());
 958:  data_out.writeInt(modifiers);
 959:  
 960:  // the replacement of '/' with '.' was needed to make computed
 961:  // SUID's agree with those computed by JDK
 962:  data_out.writeUTF
 963:  (TypeSignature.getEncodingOfMethod(method).replace('/', '.'));
 964:  }
 965:  
 966:  data_out.close();
 967:  byte[] sha = md.digest();
 968:  result = 0;
 969:  int len = sha.length < 8 ? sha.length : 8;
 970:  for (int i = 0; i < len; i++)
 971:  result += (long) (sha[i] & 0xFF) << (8 * i);
 972: 
 973:  return result;
 974:  }
 975: 
 976:  /**
 977:  * Returns the value of CLAZZ's private static final field named
 978:  * `serialPersistentFields'. It performs some sanity checks before
 979:  * returning the real array. Besides, the returned array is a clean
 980:  * copy of the original. So it can be modified.
 981:  *
 982:  * @param clazz Class to retrieve 'serialPersistentFields' from.
 983:  * @return The content of 'serialPersistentFields'.
 984:  */
 985:  private ObjectStreamField[] getSerialPersistentFields(Class clazz) 
 986:  throws NoSuchFieldException, IllegalAccessException
 987:  {
 988:  ObjectStreamField[] fieldsArray = null;
 989:  ObjectStreamField[] o;
 990: 
 991:  // Use getDeclaredField rather than getField for the same reason
 992:  // as above in getDefinedSUID.
 993:  Field f = clazz.getDeclaredField("serialPersistentFields");
 994:  f.setAccessible(true);
 995: 
 996:  int modifiers = f.getModifiers();
 997:  if (!(Modifier.isStatic(modifiers) &&
 998:  Modifier.isFinal(modifiers) &&
 999:  Modifier.isPrivate(modifiers)))
1000:  return null;
1001:  
1002:  o = (ObjectStreamField[]) f.get(null);
1003:  
1004:  if (o == null)
1005:  return null;
1006: 
1007:  fieldsArray = new ObjectStreamField[ o.length ];
1008:  System.arraycopy(o, 0, fieldsArray, 0, o.length);
1009: 
1010:  return fieldsArray;
1011:  }
1012: 
1013:  /**
1014:  * Returns a new instance of the Class this ObjectStreamClass corresponds
1015:  * to.
1016:  * Note that this should only be used for Externalizable classes.
1017:  *
1018:  * @return A new instance.
1019:  */
1020:  Externalizable newInstance() throws InvalidClassException
1021:  {
1022:  synchronized(this)
1023:  {
1024:  if (constructor == null)
1025:  {
1026:  try
1027:  {
1028:  final Constructor c = clazz.getConstructor(new Class[0]);
1029: 
1030:  AccessController.doPrivileged(new PrivilegedAction()
1031:  {
1032:  public Object run()
1033:  {
1034:  c.setAccessible(true);
1035:  return null;
1036:  }
1037:  });
1038: 
1039:  constructor = c;
1040:  }
1041:  catch(NoSuchMethodException x)
1042:  {
1043:  throw new InvalidClassException(clazz.getName(),
1044:  "No public zero-argument constructor");
1045:  }
1046:  }
1047:  }
1048: 
1049:  try
1050:  {
1051:  return (Externalizable)constructor.newInstance(null);
1052:  }
1053:  catch(Exception x)
1054:  {
1055:  throw (InvalidClassException)
1056:  new InvalidClassException(clazz.getName(),
1057:  "Unable to instantiate").initCause(x);
1058:  }
1059:  }
1060: 
1061:  public static final ObjectStreamField[] NO_FIELDS = {};
1062: 
1063:  private static Hashtable<Class,ObjectStreamClass> classLookupTable
1064:  = new Hashtable<Class,ObjectStreamClass>();
1065:  private static final NullOutputStream nullOutputStream = new NullOutputStream();
1066:  private static final Comparator interfaceComparator = new InterfaceComparator();
1067:  private static final Comparator memberComparator = new MemberComparator();
1068:  private static final
1069:  Class[] writeMethodArgTypes = { java.io.ObjectOutputStream.class };
1070: 
1071:  private ObjectStreamClass superClass;
1072:  private Class<?> clazz;
1073:  private String name;
1074:  private long uid;
1075:  private byte flags;
1076: 
1077:  // this field is package protected so that ObjectInputStream and
1078:  // ObjectOutputStream can access it directly
1079:  ObjectStreamField[] fields;
1080: 
1081:  // these are accessed by ObjectIn/OutputStream
1082:  int primFieldSize = -1; // -1 if not yet calculated
1083:  int objectFieldCount;
1084: 
1085:  Method readObjectMethod;
1086:  Method readResolveMethod;
1087:  Method writeReplaceMethod;
1088:  Method writeObjectMethod;
1089:  boolean realClassIsSerializable;
1090:  boolean realClassIsExternalizable;
1091:  ObjectStreamField[] fieldMapping;
1092:  Constructor firstNonSerializableParentConstructor;
1093:  private Constructor constructor; // default constructor for Externalizable
1094: 
1095:  boolean isProxyClass = false;
1096: 
1097:  // This is probably not necessary because this class is special cased already
1098:  // but it will avoid showing up as a discrepancy when comparing SUIDs.
1099:  private static final long serialVersionUID = -6120832682080437368L;
1100: 
1101: 
1102:  // interfaces are compared only by name
1103:  private static final class InterfaceComparator implements Comparator
1104:  {
1105:  public int compare(Object o1, Object o2)
1106:  {
1107:  return ((Class) o1).getName().compareTo(((Class) o2).getName());
1108:  }
1109:  }
1110: 
1111: 
1112:  // Members (Methods and Constructors) are compared first by name,
1113:  // conflicts are resolved by comparing type signatures
1114:  private static final class MemberComparator implements Comparator
1115:  {
1116:  public int compare(Object o1, Object o2)
1117:  {
1118:  Member m1 = (Member) o1;
1119:  Member m2 = (Member) o2;
1120: 
1121:  int comp = m1.getName().compareTo(m2.getName());
1122: 
1123:  if (comp == 0)
1124:  return TypeSignature.getEncodingOfMember(m1).
1125:  compareTo(TypeSignature.getEncodingOfMember(m2));
1126:  else
1127:  return comp;
1128:  }
1129:  }
1130: }
Overview Package Class Use Source Tree Index Deprecated About
GNU Classpath (0.95)

AltStyle によって変換されたページ (->オリジナル) /