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