1 |
/* ObjectStreamClass.java -- Class used to write class information |
/* ObjectStreamClass.java -- Class used to write class information |
2 |
about serialized objects. |
about serialized objects. |
3 |
Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc. |
Copyright (C) 1998, 1999, 2000, 2001, 2003 Free Software Foundation, Inc. |
4 |
|
|
5 |
This file is part of GNU Classpath. |
This file is part of GNU Classpath. |
6 |
|
|
48 |
import java.security.DigestOutputStream; |
import java.security.DigestOutputStream; |
49 |
import java.security.MessageDigest; |
import java.security.MessageDigest; |
50 |
import java.security.NoSuchAlgorithmException; |
import java.security.NoSuchAlgorithmException; |
51 |
|
import java.security.Security; |
52 |
import java.util.Arrays; |
import java.util.Arrays; |
53 |
import java.util.Comparator; |
import java.util.Comparator; |
54 |
import java.util.Hashtable; |
import java.util.Hashtable; |
55 |
import java.util.Vector; |
import java.util.Vector; |
56 |
import gnu.java.io.NullOutputStream; |
import gnu.java.io.NullOutputStream; |
57 |
import gnu.java.lang.reflect.TypeSignature; |
import gnu.java.lang.reflect.TypeSignature; |
58 |
import gnu.classpath.Configuration; |
import gnu.java.security.provider.Gnu; |
59 |
|
|
60 |
|
|
61 |
public class ObjectStreamClass implements Serializable |
public class ObjectStreamClass implements Serializable |
62 |
{ |
{ |
262 |
} |
} |
263 |
|
|
264 |
|
|
|
final boolean isProxyClass() |
|
|
{ |
|
|
return _isProxyClass; |
|
|
} |
|
|
|
|
|
|
|
265 |
ObjectStreamClass (String name, long uid, byte flags, |
ObjectStreamClass (String name, long uid, byte flags, |
266 |
ObjectStreamField[] fields) |
ObjectStreamField[] fields) |
267 |
{ |
{ |
271 |
this.fields = fields; |
this.fields = fields; |
272 |
} |
} |
273 |
|
|
274 |
|
void setClass (Class cl) throws InvalidClassException |
|
void setClass (Class clazz) |
|
275 |
{ |
{ |
276 |
_isProxyClass = Proxy.isProxyClass(clazz); |
this.clazz = cl; |
277 |
this.clazz = clazz; |
|
278 |
|
long class_uid = getClassUID (cl); |
279 |
|
if (uid == 0) |
280 |
|
uid = class_uid; |
281 |
|
else |
282 |
|
{ |
283 |
|
// Check that the actual UID of the resolved class matches the UID from |
284 |
|
// the stream. |
285 |
|
if (uid != class_uid) |
286 |
|
{ |
287 |
|
String msg = cl + |
288 |
|
": Local class not compatible: stream serialVersionUID=" |
289 |
|
+ uid + ", local serialVersionUID=" + class_uid; |
290 |
|
throw new InvalidClassException (msg); |
291 |
|
} |
292 |
|
} |
293 |
|
|
294 |
|
isProxyClass = clazz != null && Proxy.isProxyClass (clazz); |
295 |
ObjectStreamClass osc = (ObjectStreamClass)classLookupTable.get (clazz); |
ObjectStreamClass osc = (ObjectStreamClass)classLookupTable.get (clazz); |
296 |
if (osc == null) |
if (osc == null) |
297 |
classLookupTable.put (clazz, this); |
classLookupTable.put (clazz, this); |
299 |
calculateOffsets (); |
calculateOffsets (); |
300 |
} |
} |
301 |
|
|
|
|
|
302 |
void setSuperclass (ObjectStreamClass osc) |
void setSuperclass (ObjectStreamClass osc) |
303 |
{ |
{ |
304 |
superClass = osc; |
superClass = osc; |
349 |
{ |
{ |
350 |
uid = 0; |
uid = 0; |
351 |
flags = 0; |
flags = 0; |
352 |
_isProxyClass = Proxy.isProxyClass (cl); |
isProxyClass = Proxy.isProxyClass (cl); |
353 |
|
|
354 |
clazz = cl; |
clazz = cl; |
355 |
name = cl.getName (); |
name = cl.getName (); |
356 |
setFlags (cl); |
setFlags (cl); |
357 |
setFields (cl); |
setFields (cl); |
358 |
// to those class nonserializable, its uid field is 0 |
// to those class nonserializable, its uid field is 0 |
359 |
if ( (Serializable.class).isAssignableFrom (cl) ) |
if ( (Serializable.class).isAssignableFrom (cl) && !isProxyClass) |
360 |
setUID (cl); |
uid = getClassUID (cl); |
361 |
superClass = lookup (cl.getSuperclass ()); |
superClass = lookup (cl.getSuperclass ()); |
362 |
} |
} |
363 |
|
|
401 |
{ |
{ |
402 |
Field serialPersistentFields |
Field serialPersistentFields |
403 |
= cl.getDeclaredField ("serialPersistentFields"); |
= cl.getDeclaredField ("serialPersistentFields"); |
404 |
|
serialPersistentFields.setAccessible(true); |
405 |
int modifiers = serialPersistentFields.getModifiers (); |
int modifiers = serialPersistentFields.getModifiers (); |
406 |
|
|
407 |
if (Modifier.isStatic (modifiers) |
if (Modifier.isStatic (modifiers) |
438 |
if (all_fields[from] != null) |
if (all_fields[from] != null) |
439 |
{ |
{ |
440 |
Field f = all_fields[from]; |
Field f = all_fields[from]; |
441 |
String name = f.getName(); |
fields[to] = new ObjectStreamField (f.getName (), f.getType ()); |
|
// here is a hack to interoperate with JDK |
|
|
/* if Throwable is not align with serialized form of Java API spec, |
|
|
you should uncomment the following two line. |
|
|
if (name.equals("message") && getName().equals("java.lang.Throwable")) |
|
|
name = "detailMessage"; |
|
|
*/ |
|
|
fields[to] = new ObjectStreamField (name, f.getType ()); |
|
442 |
to++; |
to++; |
443 |
} |
} |
444 |
|
|
446 |
calculateOffsets (); |
calculateOffsets (); |
447 |
} |
} |
448 |
|
|
449 |
// Sets uid to be serial version UID defined by class, or if that |
// Returns the serial version UID defined by class, or if that |
450 |
// isn't present, calculates value of serial version UID. |
// isn't present, calculates value of serial version UID. |
451 |
private void setUID (Class cl) |
private long getClassUID (Class cl) |
452 |
{ |
{ |
453 |
try |
try |
454 |
{ |
{ |
455 |
|
// Use getDeclaredField rather than getField, since serialVersionUID |
456 |
|
// may not be public AND we only want the serialVersionUID of this |
457 |
|
// class, not a superclass or interface. |
458 |
Field suid = cl.getDeclaredField ("serialVersionUID"); |
Field suid = cl.getDeclaredField ("serialVersionUID"); |
459 |
|
suid.setAccessible(true); |
460 |
int modifiers = suid.getModifiers (); |
int modifiers = suid.getModifiers (); |
461 |
|
|
462 |
if (Modifier.isStatic (modifiers) |
if (Modifier.isStatic (modifiers) |
463 |
&& Modifier.isFinal (modifiers)) |
&& Modifier.isFinal (modifiers) |
464 |
{ |
&& suid.getType() == Long.TYPE) |
465 |
uid = getDefinedSUID (cl); |
return suid.getLong (null); |
|
return; |
|
|
} |
|
466 |
} |
} |
467 |
catch (NoSuchFieldException ignore) |
catch (NoSuchFieldException ignore) |
468 |
{} |
{} |
469 |
|
catch (IllegalAccessException ignore) |
470 |
|
{} |
471 |
|
|
472 |
// cl didn't define serialVersionUID, so we have to compute it |
// cl didn't define serialVersionUID, so we have to compute it |
473 |
try |
try |
474 |
{ |
{ |
475 |
MessageDigest md = MessageDigest.getInstance ("SHA"); |
MessageDigest md; |
476 |
|
try |
477 |
|
{ |
478 |
|
md = MessageDigest.getInstance ("SHA"); |
479 |
|
} |
480 |
|
catch (NoSuchAlgorithmException e) |
481 |
|
{ |
482 |
|
// If a provider already provides SHA, use it; otherwise, use this. |
483 |
|
Gnu gnuProvider = new Gnu(); |
484 |
|
Security.addProvider(gnuProvider); |
485 |
|
md = MessageDigest.getInstance ("SHA"); |
486 |
|
} |
487 |
|
|
488 |
DigestOutputStream digest_out = |
DigestOutputStream digest_out = |
489 |
new DigestOutputStream (nullOutputStream, md); |
new DigestOutputStream (nullOutputStream, md); |
490 |
DataOutputStream data_out = new DataOutputStream (digest_out); |
DataOutputStream data_out = new DataOutputStream (digest_out); |
525 |
} |
} |
526 |
|
|
527 |
// write class initializer method if present |
// write class initializer method if present |
528 |
boolean has_init; |
if (hasClassInitializer (cl)) |
|
try |
|
|
{ |
|
|
has_init = hasClassInitializer (cl); |
|
|
} |
|
|
catch (NoSuchMethodError e) |
|
|
{ |
|
|
has_init = false; |
|
|
} |
|
|
|
|
|
if (has_init) |
|
529 |
{ |
{ |
530 |
data_out.writeUTF ("<clinit>"); |
data_out.writeUTF ("<clinit>"); |
531 |
data_out.writeInt (Modifier.STATIC); |
data_out.writeInt (Modifier.STATIC); |
577 |
for (int i=0; i < len; i++) |
for (int i=0; i < len; i++) |
578 |
result += (long)(sha[i] & 0xFF) << (8 * i); |
result += (long)(sha[i] & 0xFF) << (8 * i); |
579 |
|
|
580 |
uid = result; |
return result; |
581 |
} |
} |
582 |
catch (NoSuchAlgorithmException e) |
catch (NoSuchAlgorithmException e) |
583 |
{ |
{ |
584 |
throw new RuntimeException ("The SHA algorithm was not found to use in computing the Serial Version UID for class " |
throw new RuntimeException ("The SHA algorithm was not found to use in computing the Serial Version UID for class " |
585 |
+ cl.getName ()); |
+ cl.getName (), e); |
586 |
} |
} |
587 |
catch (IOException ioe) |
catch (IOException ioe) |
588 |
{ |
{ |
589 |
throw new RuntimeException (ioe.getMessage ()); |
throw new RuntimeException (ioe); |
590 |
} |
} |
591 |
} |
} |
592 |
|
|
|
|
|
|
// Returns the value of CLAZZ's final static long field named |
|
|
// `serialVersionUID'. |
|
|
private long getDefinedSUID (Class clazz) |
|
|
{ |
|
|
long l = 0; |
|
|
try |
|
|
{ |
|
|
// Use getDeclaredField rather than getField, since serialVersionUID |
|
|
// may not be public AND we only want the serialVersionUID of this |
|
|
// class, not a superclass or interface. |
|
|
Field f = clazz.getDeclaredField ("serialVersionUID"); |
|
|
l = f.getLong (null); |
|
|
} |
|
|
catch (java.lang.NoSuchFieldException e) |
|
|
{ |
|
|
} |
|
|
|
|
|
catch (java.lang.IllegalAccessException e) |
|
|
{ |
|
|
} |
|
|
|
|
|
return l; |
|
|
} |
|
|
|
|
593 |
// Returns the value of CLAZZ's private static final field named |
// Returns the value of CLAZZ's private static final field named |
594 |
// `serialPersistentFields'. |
// `serialPersistentFields'. |
595 |
private ObjectStreamField[] getSerialPersistentFields (Class clazz) |
private ObjectStreamField[] getSerialPersistentFields (Class clazz) |
600 |
// Use getDeclaredField rather than getField for the same reason |
// Use getDeclaredField rather than getField for the same reason |
601 |
// as above in getDefinedSUID. |
// as above in getDefinedSUID. |
602 |
Field f = clazz.getDeclaredField ("getSerialPersistentFields"); |
Field f = clazz.getDeclaredField ("getSerialPersistentFields"); |
603 |
|
f.setAccessible(true); |
604 |
o = (ObjectStreamField[])f.get (null); |
o = (ObjectStreamField[])f.get (null); |
605 |
} |
} |
606 |
catch (java.lang.NoSuchFieldException e) |
catch (java.lang.NoSuchFieldException e) |
616 |
|
|
617 |
// Returns true if CLAZZ has a static class initializer |
// Returns true if CLAZZ has a static class initializer |
618 |
// (a.k.a. <clinit>). |
// (a.k.a. <clinit>). |
|
// |
|
|
// A NoSuchMethodError is raised if CLAZZ has no such method. |
|
619 |
private static boolean hasClassInitializer (Class clazz) |
private static boolean hasClassInitializer (Class clazz) |
|
throws java.lang.NoSuchMethodError |
|
620 |
{ |
{ |
621 |
Method m = null; |
Method m = null; |
622 |
|
|
623 |
try |
try |
624 |
{ |
{ |
625 |
/* |
/* |
626 |
* There exists a problem here, JDK run of |
* There exists a problem here, according to the spec |
627 |
* clazz.getDeclaredMethod ("<clinit>", classArgs); |
* clazz.getDeclaredMethod ("<clinit>", classArgs); |
628 |
* will always throw NoSuchMethodException, even the static |
* will always throw NoSuchMethodException, even if the static |
629 |
* intializer does exist. |
* intializer does exist. |
630 |
*/ |
*/ |
631 |
Class classArgs[] = {}; |
Class classArgs[] = {}; |
633 |
} |
} |
634 |
catch (java.lang.NoSuchMethodException e) |
catch (java.lang.NoSuchMethodException e) |
635 |
{ |
{ |
|
throw new java.lang.NoSuchMethodError (); |
|
636 |
} |
} |
637 |
|
|
638 |
return m != null; |
return m != null; |
661 |
int primFieldSize = -1; // -1 if not yet calculated |
int primFieldSize = -1; // -1 if not yet calculated |
662 |
int objectFieldCount; |
int objectFieldCount; |
663 |
|
|
664 |
boolean _isProxyClass = false; |
boolean isProxyClass = false; |
665 |
|
|
666 |
// This is probably not necessary because this class is special cased already |
// This is probably not necessary because this class is special cased already |
667 |
// but it will avoid showing up as a discrepancy when comparing SUIDs. |
// but it will avoid showing up as a discrepancy when comparing SUIDs. |
668 |
private static final long serialVersionUID = -6120832682080437368L; |
private static final long serialVersionUID = -6120832682080437368L; |
669 |
|
|
|
static |
|
|
{ |
|
|
if (Configuration.INIT_LOAD_LIBRARY) |
|
|
{ |
|
|
System.loadLibrary ("javaio"); |
|
|
} |
|
|
} |
|
670 |
} |
} |
671 |
|
|
672 |
|
|