OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libjava/] [classpath/] [java/] [io/] [ObjectStreamClass.java] - Blame information for rev 791

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 771 jeremybenn
/* 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 = 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
/* GCJ LOCAL */
658
  // FIXME: This is a workaround for a fairly obscure bug that happens
659
  // when reading a Proxy and then writing it back out again.  The
660
  // result is that the ObjectStreamClass doesn't have its fields set,
661
  // generating a NullPointerException.  Rather than this kludge we
662
  // should probably fix the real bug, but it would require a fairly
663
  // radical reorganization to do so.
664
  final void ensureFieldsSet(Class cl)
665
  {
666
    if (! fieldsSet)
667
      setFields(cl);
668
  }
669
/* END GCJ LOCAL */
670
 
671
 
672
  // Sets fields to be a sorted array of the serializable fields of
673
  // clazz.
674
  private void setFields(Class cl)
675
  {
676
/* GCJ LOCAL */
677
    fieldsSet = true;
678
/* END GCJ LOCAL */
679
 
680
    SetAccessibleAction setAccessible = new SetAccessibleAction();
681
 
682
    if (!isSerializable() || isExternalizable() || isEnum())
683
      {
684
        fields = NO_FIELDS;
685
        return;
686
      }
687
 
688
    try
689
      {
690
        final Field f =
691
          cl.getDeclaredField("serialPersistentFields");
692
        setAccessible.setMember(f);
693
        AccessController.doPrivileged(setAccessible);
694
        int modifiers = f.getModifiers();
695
 
696
        if (Modifier.isStatic(modifiers)
697
            && Modifier.isFinal(modifiers)
698
            && Modifier.isPrivate(modifiers))
699
          {
700
            fields = getSerialPersistentFields(cl);
701
            if (fields != null)
702
              {
703
                ObjectStreamField[] fieldsName = new ObjectStreamField[fields.length];
704
                System.arraycopy(fields, 0, fieldsName, 0, fields.length);
705
 
706
                Arrays.sort (fieldsName, new Comparator() {
707
                        public int compare(Object o1, Object o2)
708
                        {
709
                          ObjectStreamField f1 = (ObjectStreamField)o1;
710
                          ObjectStreamField f2 = (ObjectStreamField)o2;
711
 
712
                          return f1.getName().compareTo(f2.getName());
713
                        }
714
                    });
715
 
716
                for (int i=1; i < fields.length; i++)
717
                  {
718
                    if (fieldsName[i-1].getName().equals(fieldsName[i].getName()))
719
                        {
720
                            fields = INVALID_FIELDS;
721
                            return;
722
                        }
723
                  }
724
 
725
                Arrays.sort (fields);
726
                // Retrieve field reference.
727
                for (int i=0; i < fields.length; i++)
728
                  {
729
                    try
730
                      {
731
                        fields[i].lookupField(cl);
732
                      }
733
                    catch (NoSuchFieldException _)
734
                      {
735
                        fields[i].setToSet(false);
736
                      }
737
                  }
738
 
739
                calculateOffsets();
740
                return;
741
              }
742
          }
743
      }
744
    catch (NoSuchFieldException ignore)
745
      {
746
      }
747
    catch (IllegalAccessException ignore)
748
      {
749
      }
750
 
751
    int num_good_fields = 0;
752
    Field[] all_fields = cl.getDeclaredFields();
753
 
754
    int modifiers;
755
    // set non-serializable fields to null in all_fields
756
    for (int i = 0; i < all_fields.length; i++)
757
      {
758
        modifiers = all_fields[i].getModifiers();
759
        if (Modifier.isTransient(modifiers)
760
            || Modifier.isStatic(modifiers))
761
          all_fields[i] = null;
762
        else
763
          num_good_fields++;
764
      }
765
 
766
    // make a copy of serializable (non-null) fields
767
    fields = new ObjectStreamField[ num_good_fields ];
768
    for (int from = 0, to = 0; from < all_fields.length; from++)
769
      if (all_fields[from] != null)
770
        {
771
          final Field f = all_fields[from];
772
          setAccessible.setMember(f);
773
          AccessController.doPrivileged(setAccessible);
774
          fields[to] = new ObjectStreamField(all_fields[from]);
775
          to++;
776
        }
777
 
778
    Arrays.sort(fields);
779
    // Make sure we don't have any duplicate field names
780
    // (Sun JDK 1.4.1. throws an Internal Error as well)
781
    for (int i = 1; i < fields.length; i++)
782
      {
783
        if(fields[i - 1].getName().equals(fields[i].getName()))
784
            throw new InternalError("Duplicate field " +
785
                        fields[i].getName() + " in class " + cl.getName());
786
      }
787
    calculateOffsets();
788
  }
789
 
790
  static Hashtable uidCache = new Hashtable();
791
 
792
  // Returns the serial version UID defined by class, or if that
793
  // isn't present, calculates value of serial version UID.
794
  private long getClassUID(Class cl)
795
  {
796
    long result = 0;
797
    Long cache = (Long) uidCache.get(cl);
798
    if (cache != null)
799
      result = cache.longValue();
800
    else
801
      {
802
        // Note that we can't use Class.isEnum() here, because that returns
803
        // false for java.lang.Enum and enum value sub classes.
804
        if (Enum.class.isAssignableFrom(cl) || Proxy.isProxyClass(cl))
805
          {
806
            // Spec says that enums and dynamic proxies have
807
            // a serialVersionUID of 0L.
808
            return 0L;
809
          }
810
        try
811
          {
812
            result = getClassUIDFromField(cl);
813
          }
814
        catch (NoSuchFieldException ignore)
815
          {
816
            try
817
              {
818
                result = calculateClassUID(cl);
819
              }
820
            catch (NoSuchAlgorithmException e)
821
              {
822
                throw new RuntimeException
823
                  ("The SHA algorithm was not found to use in computing the Serial Version UID for class "
824
                   + cl.getName(), e);
825
              }
826
            catch (IOException ioe)
827
              {
828
                throw new RuntimeException(ioe);
829
              }
830
          }
831
 
832
        if (loadedByBootOrApplicationClassLoader(cl))
833
          uidCache.put(cl,Long.valueOf(result));
834
      }
835
    return result;
836
  }
837
 
838
  /**
839
   * Search for a serialVersionUID field in the given class and read
840
   * its value.
841
   *
842
   * @return the contents of the serialVersionUID field
843
   *
844
   * @throws NoSuchFieldException if such a field does not exist or is
845
   * not static, not final, not of type Long or not accessible.
846
   */
847
  long getClassUIDFromField(Class cl)
848
    throws NoSuchFieldException
849
  {
850
    long result;
851
 
852
    try
853
      {
854
        // Use getDeclaredField rather than getField, since serialVersionUID
855
        // may not be public AND we only want the serialVersionUID of this
856
        // class, not a superclass or interface.
857
        final Field suid = cl.getDeclaredField("serialVersionUID");
858
        SetAccessibleAction setAccessible = new SetAccessibleAction(suid);
859
        AccessController.doPrivileged(setAccessible);
860
        int modifiers = suid.getModifiers();
861
 
862
        if (Modifier.isStatic(modifiers)
863
            && Modifier.isFinal(modifiers)
864
            && suid.getType() == Long.TYPE)
865
          result = suid.getLong(null);
866
        else
867
          throw new NoSuchFieldException();
868
      }
869
    catch (IllegalAccessException ignore)
870
      {
871
        throw new NoSuchFieldException();
872
      }
873
 
874
    return result;
875
  }
876
 
877
  /**
878
   * Calculate class serial version UID for a class that does not
879
   * define serialVersionUID:
880
   *
881
   * @param cl a class
882
   *
883
   * @return the calculated serial varsion UID.
884
   *
885
   * @throws NoSuchAlgorithmException if SHA algorithm not found
886
   *
887
   * @throws IOException if writing to the DigestOutputStream causes
888
   * an IOException.
889
   */
890
  long calculateClassUID(Class cl)
891
    throws NoSuchAlgorithmException, IOException
892
  {
893
    long result;
894
    MessageDigest md;
895
    try
896
      {
897
        md = MessageDigest.getInstance("SHA");
898
      }
899
    catch (NoSuchAlgorithmException e)
900
      {
901
        // If a provider already provides SHA, use it; otherwise, use this.
902
        Gnu gnuProvider = new Gnu();
903
        Security.addProvider(gnuProvider);
904
        md = MessageDigest.getInstance("SHA");
905
      }
906
 
907
    DigestOutputStream digest_out =
908
      new DigestOutputStream(nullOutputStream, md);
909
    DataOutputStream data_out = new DataOutputStream(digest_out);
910
 
911
    data_out.writeUTF(cl.getName());
912
 
913
    int modifiers = cl.getModifiers();
914
    // just look at interesting bits
915
    modifiers = modifiers & (Modifier.ABSTRACT | Modifier.FINAL
916
                             | Modifier.INTERFACE | Modifier.PUBLIC);
917
    data_out.writeInt(modifiers);
918
 
919
    // Pretend that an array has no interfaces, because when array
920
    // serialization was defined (JDK 1.1), arrays didn't have it.
921
    if (! cl.isArray())
922
      {
923
        Class[] interfaces = cl.getInterfaces();
924
        Arrays.sort(interfaces, interfaceComparator);
925
        for (int i = 0; i < interfaces.length; i++)
926
          data_out.writeUTF(interfaces[i].getName());
927
      }
928
 
929
    Field field;
930
    Field[] fields = cl.getDeclaredFields();
931
    Arrays.sort(fields, memberComparator);
932
    for (int i = 0; i < fields.length; i++)
933
      {
934
        field = fields[i];
935
        modifiers = field.getModifiers();
936
        if (Modifier.isPrivate(modifiers)
937
            && (Modifier.isStatic(modifiers)
938
                || Modifier.isTransient(modifiers)))
939
          continue;
940
 
941
        data_out.writeUTF(field.getName());
942
        data_out.writeInt(modifiers);
943
        data_out.writeUTF(TypeSignature.getEncodingOfClass (field.getType()));
944
      }
945
 
946
    // write class initializer method if present
947
    if (VMObjectStreamClass.hasClassInitializer(cl))
948
      {
949
        data_out.writeUTF("<clinit>");
950
        data_out.writeInt(Modifier.STATIC);
951
        data_out.writeUTF("()V");
952
      }
953
 
954
    Constructor constructor;
955
    Constructor[] constructors = cl.getDeclaredConstructors();
956
    Arrays.sort (constructors, memberComparator);
957
    for (int i = 0; i < constructors.length; i++)
958
      {
959
        constructor = constructors[i];
960
        modifiers = constructor.getModifiers();
961
        if (Modifier.isPrivate(modifiers))
962
          continue;
963
 
964
        data_out.writeUTF("<init>");
965
        data_out.writeInt(modifiers);
966
 
967
        // the replacement of '/' with '.' was needed to make computed
968
        // SUID's agree with those computed by JDK
969
        data_out.writeUTF
970
          (TypeSignature.getEncodingOfConstructor(constructor).replace('/','.'));
971
      }
972
 
973
    Method method;
974
    Method[] methods = cl.getDeclaredMethods();
975
    Arrays.sort(methods, memberComparator);
976
    for (int i = 0; i < methods.length; i++)
977
      {
978
        method = methods[i];
979
        modifiers = method.getModifiers();
980
        if (Modifier.isPrivate(modifiers))
981
          continue;
982
 
983
        data_out.writeUTF(method.getName());
984
        data_out.writeInt(modifiers);
985
 
986
        // the replacement of '/' with '.' was needed to make computed
987
        // SUID's agree with those computed by JDK
988
        data_out.writeUTF
989
          (TypeSignature.getEncodingOfMethod(method).replace('/', '.'));
990
      }
991
 
992
    data_out.close();
993
    byte[] sha = md.digest();
994
    result = 0;
995
    int len = sha.length < 8 ? sha.length : 8;
996
    for (int i = 0; i < len; i++)
997
      result += (long) (sha[i] & 0xFF) << (8 * i);
998
 
999
    return result;
1000
  }
1001
 
1002
  /**
1003
   * Returns the value of CLAZZ's private static final field named
1004
   * `serialPersistentFields'. It performs some sanity checks before
1005
   * returning the real array. Besides, the returned array is a clean
1006
   * copy of the original. So it can be modified.
1007
   *
1008
   * @param clazz Class to retrieve 'serialPersistentFields' from.
1009
   * @return The content of 'serialPersistentFields'.
1010
   */
1011
  private ObjectStreamField[] getSerialPersistentFields(Class clazz)
1012
    throws NoSuchFieldException, IllegalAccessException
1013
  {
1014
    ObjectStreamField[] fieldsArray = null;
1015
    ObjectStreamField[] o;
1016
 
1017
    // Use getDeclaredField rather than getField for the same reason
1018
    // as above in getDefinedSUID.
1019
    Field f = clazz.getDeclaredField("serialPersistentFields");
1020
    f.setAccessible(true);
1021
 
1022
    int modifiers = f.getModifiers();
1023
    if (!(Modifier.isStatic(modifiers) &&
1024
          Modifier.isFinal(modifiers) &&
1025
          Modifier.isPrivate(modifiers)))
1026
      return null;
1027
 
1028
    o = (ObjectStreamField[]) f.get(null);
1029
 
1030
    if (o == null)
1031
      return null;
1032
 
1033
    fieldsArray = new ObjectStreamField[ o.length ];
1034
    System.arraycopy(o, 0, fieldsArray, 0, o.length);
1035
 
1036
    return fieldsArray;
1037
  }
1038
 
1039
  /**
1040
   * Returns a new instance of the Class this ObjectStreamClass corresponds
1041
   * to.
1042
   * Note that this should only be used for Externalizable classes.
1043
   *
1044
   * @return A new instance.
1045
   */
1046
  Externalizable newInstance() throws InvalidClassException
1047
  {
1048
    synchronized(this)
1049
    {
1050
        if (constructor == null)
1051
        {
1052
            try
1053
            {
1054
                final Constructor c = clazz.getConstructor(new Class[0]);
1055
 
1056
                AccessController.doPrivileged(new PrivilegedAction()
1057
                {
1058
                    public Object run()
1059
                    {
1060
                        c.setAccessible(true);
1061
                        return null;
1062
                    }
1063
                });
1064
 
1065
                constructor = c;
1066
            }
1067
            catch(NoSuchMethodException x)
1068
            {
1069
                throw new InvalidClassException(clazz.getName(),
1070
                    "No public zero-argument constructor");
1071
            }
1072
        }
1073
    }
1074
 
1075
    try
1076
    {
1077
        return (Externalizable)constructor.newInstance();
1078
    }
1079
    catch(Exception x)
1080
    {
1081
        throw (InvalidClassException)
1082
            new InvalidClassException(clazz.getName(),
1083
                     "Unable to instantiate").initCause(x);
1084
    }
1085
  }
1086
 
1087
  public static final ObjectStreamField[] NO_FIELDS = {};
1088
 
1089
  private static Hashtable<Class,ObjectStreamClass> classLookupTable
1090
    = new Hashtable<Class,ObjectStreamClass>();
1091
  private static final NullOutputStream nullOutputStream = new NullOutputStream();
1092
  private static final Comparator interfaceComparator = new InterfaceComparator();
1093
  private static final Comparator memberComparator = new MemberComparator();
1094
  private static final
1095
    Class[] writeMethodArgTypes = { java.io.ObjectOutputStream.class };
1096
 
1097
  private ObjectStreamClass superClass;
1098
  private Class<?> clazz;
1099
  private String name;
1100
  private long uid;
1101
  private byte flags;
1102
 
1103
  // this field is package protected so that ObjectInputStream and
1104
  // ObjectOutputStream can access it directly
1105
  ObjectStreamField[] fields;
1106
 
1107
  // these are accessed by ObjectIn/OutputStream
1108
  int primFieldSize = -1;  // -1 if not yet calculated
1109
  int objectFieldCount;
1110
 
1111
  Method readObjectMethod;
1112
  Method readResolveMethod;
1113
  Method writeReplaceMethod;
1114
  Method writeObjectMethod;
1115
  boolean realClassIsSerializable;
1116
  boolean realClassIsExternalizable;
1117
  ObjectStreamField[] fieldMapping;
1118
  Constructor firstNonSerializableParentConstructor;
1119
  private Constructor constructor;  // default constructor for Externalizable
1120
 
1121
  boolean isProxyClass = false;
1122
 
1123
/* GCJ LOCAL */
1124
  // True after setFields() has been called
1125
  private boolean fieldsSet = false;
1126
/* END GCJ LOCAL */
1127
 
1128
  // This is probably not necessary because this class is special cased already
1129
  // but it will avoid showing up as a discrepancy when comparing SUIDs.
1130
  private static final long serialVersionUID = -6120832682080437368L;
1131
 
1132
 
1133
  // interfaces are compared only by name
1134
  private static final class InterfaceComparator implements Comparator
1135
  {
1136
    public int compare(Object o1, Object o2)
1137
    {
1138
      return ((Class) o1).getName().compareTo(((Class) o2).getName());
1139
    }
1140
  }
1141
 
1142
 
1143
  // Members (Methods and Constructors) are compared first by name,
1144
  // conflicts are resolved by comparing type signatures
1145
  private static final class MemberComparator implements Comparator
1146
  {
1147
    public int compare(Object o1, Object o2)
1148
    {
1149
      Member m1 = (Member) o1;
1150
      Member m2 = (Member) o2;
1151
 
1152
      int comp = m1.getName().compareTo(m2.getName());
1153
 
1154
      if (comp == 0)
1155
        return TypeSignature.getEncodingOfMember(m1).
1156
          compareTo(TypeSignature.getEncodingOfMember(m2));
1157
      else
1158
        return comp;
1159
    }
1160
  }
1161
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.