Mon, 16 Oct 2017 15:59:03 +0800
merge
1 /*
2 * Copyright (c) 1998, 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 2012 All Rights Reserved
29 *
30 */
32 package com.sun.corba.se.impl.io;
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.Externalizable;
56 import java.io.Serializable;
58 import java.util.Arrays;
59 import java.util.Comparator;
61 import com.sun.corba.se.impl.util.RepositoryId;
63 import org.omg.CORBA.ValueMember;
65 import sun.corba.Bridge;
67 /**
68 * A ObjectStreamClass describes a class that can be serialized to a stream
69 * or a class that was serialized to a stream. It contains the name
70 * and the serialVersionUID of the class.
71 * <br>
72 * The ObjectStreamClass for a specific class loaded in this Java VM can
73 * be found using the lookup method.
74 *
75 * @author Roger Riggs
76 * @since JDK1.1
77 */
78 public class ObjectStreamClass implements java.io.Serializable {
79 private static final boolean DEBUG_SVUID = false ;
81 public static final long kDefaultUID = -1;
83 private static Object noArgsList[] = {};
84 private static Class<?> noTypesList[] = {};
86 /** true if represents enum type */
87 private boolean isEnum;
89 private static final Bridge bridge =
90 AccessController.doPrivileged(
91 new PrivilegedAction<Bridge>() {
92 public Bridge run() {
93 return Bridge.get() ;
94 }
95 }
96 ) ;
98 /** Find the descriptor for a class that can be serialized. Null
99 * is returned if the specified class does not implement
100 * java.io.Serializable or java.io.Externalizable.
101 */
102 static final ObjectStreamClass lookup(Class<?> cl)
103 {
104 ObjectStreamClass desc = lookupInternal(cl);
105 if (desc.isSerializable() || desc.isExternalizable())
106 return desc;
107 return null;
108 }
110 /*
111 * Find the class descriptor for the specified class.
112 * Package access only so it can be called from ObjectIn/OutStream.
113 */
114 static ObjectStreamClass lookupInternal(Class<?> cl)
115 {
116 /* Synchronize on the hashtable so no two threads will do
117 * this at the same time.
118 */
119 ObjectStreamClass desc = null;
120 synchronized (descriptorFor) {
121 /* Find the matching descriptor if it already known */
122 desc = findDescriptorFor(cl);
123 if (desc == null) {
124 /* Check if it's serializable */
125 boolean serializable = Serializable.class.isAssignableFrom(cl);
127 /* If the class is only Serializable,
128 * lookup the descriptor for the superclass.
129 */
130 ObjectStreamClass 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(cl, superdesc,
155 serializable, externalizable);
156 }
157 // Must always call init. See bug 4488137. This code was
158 // incorrectly changed to return immediately on a non-null
159 // cache result. That allowed threads to gain access to
160 // unintialized instances.
161 //
162 // History: Note, the following init() call was originally within
163 // the synchronization block, as it currently is now. Later, the
164 // init() call was moved outside the synchronization block, and
165 // the init() method used a private member variable lock, to
166 // avoid performance problems. See bug 4165204. But that lead to
167 // a deadlock situation, see bug 5104239. Hence, the init() method
168 // has now been moved back into the synchronization block. The
169 // right approach to solving these problems would be to rewrite
170 // this class, based on the latest java.io.ObjectStreamClass.
171 desc.init();
172 }
173 return desc;
174 }
176 /**
177 * The name of the class described by this descriptor.
178 */
179 public final String getName() {
180 return name;
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 static final long getSerialVersionUID( java.lang.Class<?> clazz) {
190 ObjectStreamClass theosc = ObjectStreamClass.lookup( clazz );
191 if( theosc != null )
192 {
193 return theosc.getSerialVersionUID( );
194 }
195 return 0;
196 }
198 /**
199 * Return the serialVersionUID for this class.
200 * The serialVersionUID defines a set of classes all with the same name
201 * that have evolved from a common root class and agree to be serialized
202 * and deserialized using a common format.
203 */
204 public final long getSerialVersionUID() {
205 return suid;
206 }
208 /**
209 * Return the serialVersionUID string for this class.
210 * The serialVersionUID defines a set of classes all with the same name
211 * that have evolved from a common root class and agree to be serialized
212 * and deserialized using a common format.
213 */
214 public final String getSerialVersionUIDStr() {
215 if (suidStr == null)
216 suidStr = Long.toHexString(suid).toUpperCase();
217 return suidStr;
218 }
220 /**
221 * Return the actual (computed) serialVersionUID for this class.
222 */
223 public static final long getActualSerialVersionUID( java.lang.Class<?> clazz )
224 {
225 ObjectStreamClass theosc = ObjectStreamClass.lookup( clazz );
226 if( theosc != null )
227 {
228 return theosc.getActualSerialVersionUID( );
229 }
230 return 0;
231 }
233 /**
234 * Return the actual (computed) serialVersionUID for this class.
235 */
236 public final long getActualSerialVersionUID() {
237 return actualSuid;
238 }
240 /**
241 * Return the actual (computed) serialVersionUID for this class.
242 */
243 public final String getActualSerialVersionUIDStr() {
244 if (actualSuidStr == null)
245 actualSuidStr = Long.toHexString(actualSuid).toUpperCase();
246 return actualSuidStr;
247 }
249 /**
250 * Return the class in the local VM that this version is mapped to.
251 * Null is returned if there is no corresponding local class.
252 */
253 public final Class<?> forClass() {
254 return ofClass;
255 }
257 /**
258 * Return an array of the fields of this serializable class.
259 * @return an array containing an element for each persistent
260 * field of this class. Returns an array of length zero if
261 * there are no fields.
262 * @since JDK1.2
263 */
264 public ObjectStreamField[] getFields() {
265 // Return a copy so the caller can't change the fields.
266 if (fields.length > 0) {
267 ObjectStreamField[] dup = new ObjectStreamField[fields.length];
268 System.arraycopy(fields, 0, dup, 0, fields.length);
269 return dup;
270 } else {
271 return fields;
272 }
273 }
275 public boolean hasField(ValueMember field)
276 {
277 try {
278 for (int i = 0; i < fields.length; i++) {
279 if (fields[i].getName().equals(field.name)) {
280 if (fields[i].getSignature().equals(
281 ValueUtility.getSignature(field)))
282 return true;
283 }
284 }
285 } catch (Exception exc) {
286 // Ignore this; all we want to do is return false
287 // Note that ValueUtility.getSignature can throw checked exceptions.
288 }
290 return false;
291 }
293 /* Avoid unnecessary allocations. */
294 final ObjectStreamField[] getFieldsNoCopy() {
295 return fields;
296 }
298 /**
299 * Get the field of this class by name.
300 * @return The ObjectStreamField object of the named field or null if there
301 * is no such named field.
302 */
303 public final ObjectStreamField getField(String name) {
304 /* Binary search of fields by name.
305 */
306 for (int i = fields.length-1; i >= 0; i--) {
307 if (name.equals(fields[i].getName())) {
308 return fields[i];
309 }
310 }
311 return null;
312 }
314 public Serializable writeReplace(Serializable value) {
315 if (writeReplaceObjectMethod != null) {
316 try {
317 return (Serializable) writeReplaceObjectMethod.invoke(value,noArgsList);
318 } catch(Throwable t) {
319 throw new RuntimeException(t);
320 }
321 }
322 else return value;
323 }
325 public Object readResolve(Object value) {
326 if (readResolveObjectMethod != null) {
327 try {
328 return readResolveObjectMethod.invoke(value,noArgsList);
329 } catch(Throwable t) {
330 throw new RuntimeException(t);
331 }
332 }
333 else return value;
334 }
336 /**
337 * Return a string describing this ObjectStreamClass.
338 */
339 public final String toString() {
340 StringBuffer sb = new StringBuffer();
342 sb.append(name);
343 sb.append(": static final long serialVersionUID = ");
344 sb.append(Long.toString(suid));
345 sb.append("L;");
346 return sb.toString();
347 }
349 /*
350 * Create a new ObjectStreamClass from a loaded class.
351 * Don't call this directly, call lookup instead.
352 */
353 private ObjectStreamClass(java.lang.Class<?> cl, ObjectStreamClass superdesc,
354 boolean serial, boolean extern)
355 {
356 ofClass = cl; /* created from this class */
358 if (Proxy.isProxyClass(cl)) {
359 forProxyClass = true;
360 }
362 name = cl.getName();
363 isEnum = Enum.class.isAssignableFrom(cl);
364 superclass = superdesc;
365 serializable = serial;
366 if (!forProxyClass) {
367 // proxy classes are never externalizable
368 externalizable = extern;
369 }
371 /*
372 * Enter this class in the table of known descriptors.
373 * Otherwise, when the fields are read it may recurse
374 * trying to find the descriptor for itself.
375 */
376 insertDescriptorFor(this);
378 /*
379 * The remainder of initialization occurs in init(), which is called
380 * after the lock on the global class descriptor table has been
381 * released.
382 */
383 }
385 private static final class PersistentFieldsValue
386 extends ClassValue<ObjectStreamField[]> {
387 PersistentFieldsValue() { }
389 protected ObjectStreamField[] computeValue(Class<?> type) {
390 try {
391 Field pf = type.getDeclaredField("serialPersistentFields");
392 int mods = pf.getModifiers();
393 if (Modifier.isPrivate(mods) && Modifier.isStatic(mods) &&
394 Modifier.isFinal(mods)) {
395 pf.setAccessible(true);
396 java.io.ObjectStreamField[] fields =
397 (java.io.ObjectStreamField[])pf.get(type);
398 return translateFields(fields);
399 }
400 } catch (NoSuchFieldException | IllegalAccessException |
401 IllegalArgumentException | ClassCastException e) {
402 }
403 return null;
404 }
406 private static ObjectStreamField[] translateFields(
407 java.io.ObjectStreamField[] fields) {
408 ObjectStreamField[] translation =
409 new ObjectStreamField[fields.length];
410 for (int i = 0; i < fields.length; i++) {
411 translation[i] = new ObjectStreamField(fields[i].getName(),
412 fields[i].getType());
413 }
414 return translation;
415 }
416 }
418 private static final PersistentFieldsValue persistentFieldsValue =
419 new PersistentFieldsValue();
421 /*
422 * Initialize class descriptor. This method is only invoked on class
423 * descriptors created via calls to lookupInternal(). This method is kept
424 * separate from the ObjectStreamClass constructor so that lookupInternal
425 * does not have to hold onto a global class descriptor table lock while the
426 * class descriptor is being initialized (see bug 4165204).
427 */
430 private void init() {
431 synchronized (lock) {
433 // See description at definition of initialized.
434 if (initialized)
435 return;
437 final Class<?> cl = ofClass;
439 if (!serializable ||
440 externalizable ||
441 forProxyClass ||
442 name.equals("java.lang.String")){
443 fields = NO_FIELDS;
444 } else if (serializable) {
445 /* Ask for permission to override field access checks.
446 */
447 AccessController.doPrivileged(new PrivilegedAction() {
448 public Object run() {
449 /* Fill in the list of persistent fields.
450 * If it is declared, use the declared serialPersistentFields.
451 * Otherwise, extract the fields from the class itself.
452 */
453 fields = persistentFieldsValue.get(cl);
455 if (fields == null) {
456 /* Get all of the declared fields for this
457 * Class. setAccessible on all fields so they
458 * can be accessed later. Create a temporary
459 * ObjectStreamField array to hold each
460 * non-static, non-transient field. Then copy the
461 * temporary array into an array of the correct
462 * size once the number of fields is known.
463 */
464 Field[] actualfields = cl.getDeclaredFields();
466 int numFields = 0;
467 ObjectStreamField[] tempFields =
468 new ObjectStreamField[actualfields.length];
469 for (int i = 0; i < actualfields.length; i++) {
470 Field fld = actualfields[i] ;
471 int modifiers = fld.getModifiers();
472 if (!Modifier.isStatic(modifiers) &&
473 !Modifier.isTransient(modifiers)) {
474 fld.setAccessible(true) ;
475 tempFields[numFields++] = new ObjectStreamField(fld);
476 }
477 }
479 fields = new ObjectStreamField[numFields];
480 System.arraycopy(tempFields, 0, fields, 0, numFields);
482 } else {
483 // For each declared persistent field, look for an actual
484 // reflected Field. If there is one, make sure it's the correct
485 // type and cache it in the ObjectStreamClass for that field.
486 for (int j = fields.length-1; j >= 0; j--) {
487 try {
488 Field reflField = cl.getDeclaredField(fields[j].getName());
489 if (fields[j].getType() == reflField.getType()) {
490 reflField.setAccessible(true);
491 fields[j].setField(reflField);
492 }
493 } catch (NoSuchFieldException e) {
494 // Nothing to do
495 }
496 }
497 }
498 return null;
499 }
500 });
502 if (fields.length > 1)
503 Arrays.sort(fields);
505 /* Set up field data for use while writing using the API api. */
506 computeFieldInfo();
507 }
509 /* Get the serialVersionUID from the class.
510 * It uses the access override mechanism so make sure
511 * the field objects is only used here.
512 *
513 * NonSerializable classes have a serialVerisonUID of 0L.
514 */
515 if (isNonSerializable() || isEnum) {
516 suid = 0L;
517 } else {
518 // Lookup special Serializable members using reflection.
519 AccessController.doPrivileged(new PrivilegedAction() {
520 public Object run() {
521 if (forProxyClass) {
522 // proxy classes always have serialVersionUID of 0L
523 suid = 0L;
524 } else {
525 try {
526 final Field f = cl.getDeclaredField("serialVersionUID");
527 int mods = f.getModifiers();
528 // SerialBug 5: static final SUID should be read
529 if (Modifier.isStatic(mods) && Modifier.isFinal(mods) ) {
530 f.setAccessible(true);
531 suid = f.getLong(cl);
532 // SerialBug 2: should be computed after writeObject
533 // actualSuid = computeStructuralUID(cl);
534 } else {
535 suid = _computeSerialVersionUID(cl);
536 // SerialBug 2: should be computed after writeObject
537 // actualSuid = computeStructuralUID(cl);
538 }
539 } catch (NoSuchFieldException ex) {
540 suid = _computeSerialVersionUID(cl);
541 // SerialBug 2: should be computed after writeObject
542 // actualSuid = computeStructuralUID(cl);
543 } catch (IllegalAccessException ex) {
544 suid = _computeSerialVersionUID(cl);
545 }
546 }
548 writeReplaceObjectMethod = ObjectStreamClass.getInheritableMethod(cl,
549 "writeReplace", noTypesList, Object.class);
551 readResolveObjectMethod = ObjectStreamClass.getInheritableMethod(cl,
552 "readResolve", noTypesList, Object.class);
554 if (externalizable)
555 cons = getExternalizableConstructor(cl) ;
556 else
557 cons = getSerializableConstructor(cl) ;
559 if (serializable && !forProxyClass) {
560 /* Look for the writeObject method
561 * Set the accessible flag on it here. ObjectOutputStream
562 * will call it as necessary.
563 */
564 writeObjectMethod = getPrivateMethod( cl, "writeObject",
565 new Class<?>[] { java.io.ObjectOutputStream.class }, Void.TYPE ) ;
566 readObjectMethod = getPrivateMethod( cl, "readObject",
567 new Class<?>[] { java.io.ObjectInputStream.class }, Void.TYPE ) ;
568 }
569 return null;
570 }
571 });
572 }
574 // This call depends on a lot of information computed above!
575 actualSuid = ObjectStreamClass.computeStructuralUID(this, cl);
577 // If we have a write object method, precompute the
578 // RMI-IIOP stream format version 2 optional data
579 // repository ID.
580 if (hasWriteObject())
581 rmiiiopOptionalDataRepId = computeRMIIIOPOptionalDataRepId();
583 // This must be done last.
584 initialized = true;
585 }
586 }
588 /**
589 * Returns non-static private method with given signature defined by given
590 * class, or null if none found. Access checks are disabled on the
591 * returned method (if any).
592 */
593 private static Method getPrivateMethod(Class<?> cl, String name,
594 Class<?>[] argTypes,
595 Class<?> returnType)
596 {
597 try {
598 Method meth = cl.getDeclaredMethod(name, argTypes);
599 meth.setAccessible(true);
600 int mods = meth.getModifiers();
601 return ((meth.getReturnType() == returnType) &&
602 ((mods & Modifier.STATIC) == 0) &&
603 ((mods & Modifier.PRIVATE) != 0)) ? meth : null;
604 } catch (NoSuchMethodException ex) {
605 return null;
606 }
607 }
609 // Specific to RMI-IIOP
610 /**
611 * Java to IDL ptc-02-01-12 1.5.1
612 *
613 * "The rep_id string passed to the start_value method must be
614 * 'RMI:org.omg.custom.class:hashcode:suid' where class is the
615 * fully-qualified name of the class whose writeObject method
616 * is being invoked and hashcode and suid are the class's hashcode
617 * and SUID."
618 */
619 private String computeRMIIIOPOptionalDataRepId() {
621 StringBuffer sbuf = new StringBuffer("RMI:org.omg.custom.");
622 sbuf.append(RepositoryId.convertToISOLatin1(this.getName()));
623 sbuf.append(':');
624 sbuf.append(this.getActualSerialVersionUIDStr());
625 sbuf.append(':');
626 sbuf.append(this.getSerialVersionUIDStr());
628 return sbuf.toString();
629 }
631 /**
632 * This will return null if there is no writeObject method.
633 */
634 public final String getRMIIIOPOptionalDataRepId() {
635 return rmiiiopOptionalDataRepId;
636 }
638 /*
639 * Create an empty ObjectStreamClass for a class about to be read.
640 * This is separate from read so ObjectInputStream can assign the
641 * wire handle early, before any nested ObjectStreamClass might
642 * be read.
643 */
644 ObjectStreamClass(String n, long s) {
645 name = n;
646 suid = s;
647 superclass = null;
648 }
651 /*
652 * Set the class this version descriptor matches.
653 * The base class name and serializable hash must match.
654 * Fill in the reflected Fields that will be used
655 * for reading.
656 */
657 final void setClass(Class<?> cl) throws InvalidClassException {
659 if (cl == null) {
660 localClassDesc = null;
661 ofClass = null;
662 computeFieldInfo();
663 return;
664 }
666 localClassDesc = lookupInternal(cl);
667 if (localClassDesc == null)
668 // XXX I18N, logging needed
669 throw new InvalidClassException(cl.getName(),
670 "Local class not compatible");
671 if (suid != localClassDesc.suid) {
673 /* Check for exceptional cases that allow mismatched suid. */
675 /* Allow adding Serializable or Externalizable
676 * to a later release of the class.
677 */
678 boolean addedSerialOrExtern =
679 isNonSerializable() || localClassDesc.isNonSerializable();
681 /* Disregard the serialVersionUID of an array
682 * when name and cl.Name differ. If resolveClass() returns
683 * an array with a different package name,
684 * the serialVersionUIDs will not match since the fully
685 * qualified array class is used in the
686 * computation of the array's serialVersionUID. There is
687 * no way to set a permanent serialVersionUID for an array type.
688 */
690 boolean arraySUID = (cl.isArray() && ! cl.getName().equals(name));
692 if (! arraySUID && ! addedSerialOrExtern ) {
693 // XXX I18N, logging needed
694 throw new InvalidClassException(cl.getName(),
695 "Local class not compatible:" +
696 " stream classdesc serialVersionUID=" + suid +
697 " local class serialVersionUID=" + localClassDesc.suid);
698 }
699 }
701 /* compare the class names, stripping off package names. */
702 if (! compareClassNames(name, cl.getName(), '.'))
703 // XXX I18N, logging needed
704 throw new InvalidClassException(cl.getName(),
705 "Incompatible local class name. " +
706 "Expected class name compatible with " +
707 name);
709 /*
710 * Test that both implement either serializable or externalizable.
711 */
713 // The next check is more generic, since it covers the
714 // Proxy case, the JDK 1.3 serialization code has
715 // both checks
716 //if ((serializable && localClassDesc.externalizable) ||
717 // (externalizable && localClassDesc.serializable))
718 // throw new InvalidClassException(localCl.getName(),
719 // "Serializable is incompatible with Externalizable");
721 if ((serializable != localClassDesc.serializable) ||
722 (externalizable != localClassDesc.externalizable) ||
723 (!serializable && !externalizable))
725 // XXX I18N, logging needed
726 throw new InvalidClassException(cl.getName(),
727 "Serialization incompatible with Externalization");
729 /* Set up the reflected Fields in the class where the value of each
730 * field in this descriptor should be stored.
731 * Each field in this ObjectStreamClass (the source) is located (by
732 * name) in the ObjectStreamClass of the class(the destination).
733 * In the usual (non-versioned case) the field is in both
734 * descriptors and the types match, so the reflected Field is copied.
735 * If the type does not match, a InvalidClass exception is thrown.
736 * If the field is not present in the class, the reflected Field
737 * remains null so the field will be read but discarded.
738 * If extra fields are present in the class they are ignored. Their
739 * values will be set to the default value by the object allocator.
740 * Both the src and dest field list are sorted by type and name.
741 */
743 ObjectStreamField[] destfield =
744 (ObjectStreamField[])localClassDesc.fields;
745 ObjectStreamField[] srcfield =
746 (ObjectStreamField[])fields;
748 int j = 0;
749 nextsrc:
750 for (int i = 0; i < srcfield.length; i++ ) {
751 /* Find this field in the dest*/
752 for (int k = j; k < destfield.length; k++) {
753 if (srcfield[i].getName().equals(destfield[k].getName())) {
754 /* found match */
755 if (srcfield[i].isPrimitive() &&
756 !srcfield[i].typeEquals(destfield[k])) {
757 // XXX I18N, logging needed
758 throw new InvalidClassException(cl.getName(),
759 "The type of field " +
760 srcfield[i].getName() +
761 " of class " + name +
762 " is incompatible.");
763 }
765 /* Skip over any fields in the dest that are not in the src */
766 j = k;
768 srcfield[i].setField(destfield[j].getField());
769 // go on to the next source field
770 continue nextsrc;
771 }
772 }
773 }
775 /* Set up field data for use while reading from the input stream. */
776 computeFieldInfo();
778 /* Remember the class this represents */
779 ofClass = cl;
781 /* get the cache of these methods from the local class
782 * implementation.
783 */
784 readObjectMethod = localClassDesc.readObjectMethod;
785 readResolveObjectMethod = localClassDesc.readResolveObjectMethod;
786 }
788 /* Compare the base class names of streamName and localName.
789 *
790 * @return Return true iff the base class name compare.
791 * @parameter streamName Fully qualified class name.
792 * @parameter localName Fully qualified class name.
793 * @parameter pkgSeparator class names use either '.' or '/'.
794 *
795 * Only compare base class name to allow package renaming.
796 */
797 static boolean compareClassNames(String streamName,
798 String localName,
799 char pkgSeparator) {
800 /* compare the class names, stripping off package names. */
801 int streamNameIndex = streamName.lastIndexOf(pkgSeparator);
802 if (streamNameIndex < 0)
803 streamNameIndex = 0;
805 int localNameIndex = localName.lastIndexOf(pkgSeparator);
806 if (localNameIndex < 0)
807 localNameIndex = 0;
809 return streamName.regionMatches(false, streamNameIndex,
810 localName, localNameIndex,
811 streamName.length() - streamNameIndex);
812 }
814 /*
815 * Compare the types of two class descriptors.
816 * They match if they have the same class name and suid
817 */
818 final boolean typeEquals(ObjectStreamClass other) {
819 return (suid == other.suid) &&
820 compareClassNames(name, other.name, '.');
821 }
823 /*
824 * Return the superclass descriptor of this descriptor.
825 */
826 final void setSuperclass(ObjectStreamClass s) {
827 superclass = s;
828 }
830 /*
831 * Return the superclass descriptor of this descriptor.
832 */
833 final ObjectStreamClass getSuperclass() {
834 return superclass;
835 }
837 /**
838 * Return whether the class has a readObject method
839 */
840 final boolean hasReadObject() {
841 return readObjectMethod != null;
842 }
844 /*
845 * Return whether the class has a writeObject method
846 */
847 final boolean hasWriteObject() {
848 return writeObjectMethod != null ;
849 }
851 /**
852 * Returns when or not this class should be custom
853 * marshaled (use chunking). This should happen if
854 * it is Externalizable OR if it or
855 * any of its superclasses has a writeObject method,
856 */
857 final boolean isCustomMarshaled() {
858 return (hasWriteObject() || isExternalizable())
859 || (superclass != null && superclass.isCustomMarshaled());
860 }
862 /*
863 * Return true if all instances of 'this' Externalizable class
864 * are written in block-data mode from the stream that 'this' was read
865 * from. <p>
866 *
867 * In JDK 1.1, all Externalizable instances are not written
868 * in block-data mode.
869 * In JDK 1.2, all Externalizable instances, by default, are written
870 * in block-data mode and the Externalizable instance is terminated with
871 * tag TC_ENDBLOCKDATA. Change enabled the ability to skip Externalizable
872 * instances.
873 *
874 * IMPLEMENTATION NOTE:
875 * This should have been a mode maintained per stream; however,
876 * for compatibility reasons, it was only possible to record
877 * this change per class. All Externalizable classes within
878 * a given stream should either have this mode enabled or
879 * disabled. This is enforced by not allowing the PROTOCOL_VERSION
880 * of a stream to he changed after any objects have been written.
881 *
882 * @see ObjectOutputStream#useProtocolVersion
883 * @see ObjectStreamConstants#PROTOCOL_VERSION_1
884 * @see ObjectStreamConstants#PROTOCOL_VERSION_2
885 *
886 * @since JDK 1.2
887 */
888 boolean hasExternalizableBlockDataMode() {
889 return hasExternalizableBlockData;
890 }
892 /**
893 * Creates a new instance of the represented class. If the class is
894 * externalizable, invokes its public no-arg constructor; otherwise, if the
895 * class is serializable, invokes the no-arg constructor of the first
896 * non-serializable superclass. Throws UnsupportedOperationException if
897 * this class descriptor is not associated with a class, if the associated
898 * class is non-serializable or if the appropriate no-arg constructor is
899 * inaccessible/unavailable.
900 */
901 Object newInstance()
902 throws InstantiationException, InvocationTargetException,
903 UnsupportedOperationException
904 {
905 if (cons != null) {
906 try {
907 return cons.newInstance(new Object[0]);
908 } catch (IllegalAccessException ex) {
909 // should not occur, as access checks have been suppressed
910 InternalError ie = new InternalError();
911 ie.initCause( ex ) ;
912 throw ie ;
913 }
914 } else {
915 throw new UnsupportedOperationException();
916 }
917 }
919 /**
920 * Returns public no-arg constructor of given class, or null if none found.
921 * Access checks are disabled on the returned constructor (if any), since
922 * the defining class may still be non-public.
923 */
924 private static Constructor getExternalizableConstructor(Class<?> cl) {
925 try {
926 Constructor cons = cl.getDeclaredConstructor(new Class<?>[0]);
927 cons.setAccessible(true);
928 return ((cons.getModifiers() & Modifier.PUBLIC) != 0) ?
929 cons : null;
930 } catch (NoSuchMethodException ex) {
931 return null;
932 }
933 }
935 /**
936 * Returns subclass-accessible no-arg constructor of first non-serializable
937 * superclass, or null if none found. Access checks are disabled on the
938 * returned constructor (if any).
939 */
940 private static Constructor getSerializableConstructor(Class<?> cl) {
941 Class<?> initCl = cl;
942 while (Serializable.class.isAssignableFrom(initCl)) {
943 if ((initCl = initCl.getSuperclass()) == null) {
944 return null;
945 }
946 }
947 try {
948 Constructor cons = initCl.getDeclaredConstructor(new Class<?>[0]);
949 int mods = cons.getModifiers();
950 if ((mods & Modifier.PRIVATE) != 0 ||
951 ((mods & (Modifier.PUBLIC | Modifier.PROTECTED)) == 0 &&
952 !packageEquals(cl, initCl)))
953 {
954 return null;
955 }
956 cons = bridge.newConstructorForSerialization(cl, cons);
957 cons.setAccessible(true);
958 return cons;
959 } catch (NoSuchMethodException ex) {
960 return null;
961 }
962 }
964 /*
965 * Return the ObjectStreamClass of the local class this one is based on.
966 */
967 final ObjectStreamClass localClassDescriptor() {
968 return localClassDesc;
969 }
971 /*
972 * Get the Serializability of the class.
973 */
974 boolean isSerializable() {
975 return serializable;
976 }
978 /*
979 * Get the externalizability of the class.
980 */
981 boolean isExternalizable() {
982 return externalizable;
983 }
985 boolean isNonSerializable() {
986 return ! (externalizable || serializable);
987 }
989 /*
990 * Calculate the size of the array needed to store primitive data and the
991 * number of object references to read when reading from the input
992 * stream.
993 */
994 private void computeFieldInfo() {
995 primBytes = 0;
996 objFields = 0;
998 for (int i = 0; i < fields.length; i++ ) {
999 switch (fields[i].getTypeCode()) {
1000 case 'B':
1001 case 'Z':
1002 primBytes += 1;
1003 break;
1004 case 'C':
1005 case 'S':
1006 primBytes += 2;
1007 break;
1009 case 'I':
1010 case 'F':
1011 primBytes += 4;
1012 break;
1013 case 'J':
1014 case 'D' :
1015 primBytes += 8;
1016 break;
1018 case 'L':
1019 case '[':
1020 objFields += 1;
1021 break;
1022 }
1023 }
1024 }
1026 private static void msg( String str )
1027 {
1028 System.out.println( str ) ;
1029 }
1031 /* JDK 1.5 has introduced some new modifier bits (such as SYNTHETIC)
1032 * that can affect the SVUID computation (see bug 4897937). These bits
1033 * must be ignored, as otherwise interoperability with ORBs in earlier
1034 * JDK versions can be compromised. I am adding these masks for this
1035 * purpose as discussed in the CCC for this bug (see http://ccc.sfbay/4897937).
1036 */
1038 public static final int CLASS_MASK = Modifier.PUBLIC | Modifier.FINAL |
1039 Modifier.INTERFACE | Modifier.ABSTRACT ;
1040 public static final int FIELD_MASK = Modifier.PUBLIC | Modifier.PRIVATE |
1041 Modifier.PROTECTED | Modifier.STATIC | Modifier.FINAL |
1042 Modifier.TRANSIENT | Modifier.VOLATILE ;
1043 public static final int METHOD_MASK = Modifier.PUBLIC | Modifier.PRIVATE |
1044 Modifier.PROTECTED | Modifier.STATIC | Modifier.FINAL |
1045 Modifier.SYNCHRONIZED | Modifier.NATIVE | Modifier.ABSTRACT |
1046 Modifier.STRICT ;
1048 /*
1049 * Compute a hash for the specified class. Incrementally add
1050 * items to the hash accumulating in the digest stream.
1051 * Fold the hash into a long. Use the SHA secure hash function.
1052 */
1053 private static long _computeSerialVersionUID(Class<?> cl) {
1054 if (DEBUG_SVUID)
1055 msg( "Computing SerialVersionUID for " + cl ) ;
1056 ByteArrayOutputStream devnull = new ByteArrayOutputStream(512);
1058 long h = 0;
1059 try {
1060 MessageDigest md = MessageDigest.getInstance("SHA");
1061 DigestOutputStream mdo = new DigestOutputStream(devnull, md);
1062 DataOutputStream data = new DataOutputStream(mdo);
1064 if (DEBUG_SVUID)
1065 msg( "\twriteUTF( \"" + cl.getName() + "\" )" ) ;
1066 data.writeUTF(cl.getName());
1068 int classaccess = cl.getModifiers();
1069 classaccess &= (Modifier.PUBLIC | Modifier.FINAL |
1070 Modifier.INTERFACE | Modifier.ABSTRACT);
1072 /* Workaround for javac bug that only set ABSTRACT for
1073 * interfaces if the interface had some methods.
1074 * The ABSTRACT bit reflects that the number of methods > 0.
1075 * This is required so correct hashes can be computed
1076 * for existing class files.
1077 * Previously this hack was previously present in the VM.
1078 */
1079 Method[] method = cl.getDeclaredMethods();
1080 if ((classaccess & Modifier.INTERFACE) != 0) {
1081 classaccess &= (~Modifier.ABSTRACT);
1082 if (method.length > 0) {
1083 classaccess |= Modifier.ABSTRACT;
1084 }
1085 }
1087 // Mask out any post-1.4 attributes
1088 classaccess &= CLASS_MASK ;
1090 if (DEBUG_SVUID)
1091 msg( "\twriteInt( " + classaccess + " ) " ) ;
1092 data.writeInt(classaccess);
1094 /*
1095 * Get the list of interfaces supported,
1096 * Accumulate their names their names in Lexical order
1097 * and add them to the hash
1098 */
1099 if (!cl.isArray()) {
1100 /* In 1.2fcs, getInterfaces() was modified to return
1101 * {java.lang.Cloneable, java.io.Serializable} when
1102 * called on array classes. These values would upset
1103 * the computation of the hash, so we explicitly omit
1104 * them from its computation.
1105 */
1107 Class<?> interfaces[] = cl.getInterfaces();
1108 Arrays.sort(interfaces, compareClassByName);
1110 for (int i = 0; i < interfaces.length; i++) {
1111 if (DEBUG_SVUID)
1112 msg( "\twriteUTF( \"" + interfaces[i].getName() + "\" ) " ) ;
1113 data.writeUTF(interfaces[i].getName());
1114 }
1115 }
1117 /* Sort the field names to get a deterministic order */
1118 Field[] field = cl.getDeclaredFields();
1119 Arrays.sort(field, compareMemberByName);
1121 for (int i = 0; i < field.length; i++) {
1122 Field f = field[i];
1124 /* Include in the hash all fields except those that are
1125 * private transient and private static.
1126 */
1127 int m = f.getModifiers();
1128 if (Modifier.isPrivate(m) &&
1129 (Modifier.isTransient(m) || Modifier.isStatic(m)))
1130 continue;
1132 if (DEBUG_SVUID)
1133 msg( "\twriteUTF( \"" + f.getName() + "\" ) " ) ;
1134 data.writeUTF(f.getName());
1136 // Mask out any post-1.4 bits
1137 m &= FIELD_MASK ;
1139 if (DEBUG_SVUID)
1140 msg( "\twriteInt( " + m + " ) " ) ;
1141 data.writeInt(m);
1143 if (DEBUG_SVUID)
1144 msg( "\twriteUTF( \"" + getSignature(f.getType()) + "\" ) " ) ;
1145 data.writeUTF(getSignature(f.getType()));
1146 }
1148 if (hasStaticInitializer(cl)) {
1149 if (DEBUG_SVUID)
1150 msg( "\twriteUTF( \"<clinit>\" ) " ) ;
1151 data.writeUTF("<clinit>");
1153 if (DEBUG_SVUID)
1154 msg( "\twriteInt( " + Modifier.STATIC + " )" ) ;
1155 data.writeInt(Modifier.STATIC); // TBD: what modifiers does it have
1157 if (DEBUG_SVUID)
1158 msg( "\twriteUTF( \"()V\" )" ) ;
1159 data.writeUTF("()V");
1160 }
1162 /*
1163 * Get the list of constructors including name and signature
1164 * Sort lexically, add all except the private constructors
1165 * to the hash with their access flags
1166 */
1168 MethodSignature[] constructors =
1169 MethodSignature.removePrivateAndSort(cl.getDeclaredConstructors());
1170 for (int i = 0; i < constructors.length; i++) {
1171 MethodSignature c = constructors[i];
1172 String mname = "<init>";
1173 String desc = c.signature;
1174 desc = desc.replace('/', '.');
1175 if (DEBUG_SVUID)
1176 msg( "\twriteUTF( \"" + mname + "\" )" ) ;
1177 data.writeUTF(mname);
1179 // mask out post-1.4 modifiers
1180 int modifier = c.member.getModifiers() & METHOD_MASK ;
1182 if (DEBUG_SVUID)
1183 msg( "\twriteInt( " + modifier + " ) " ) ;
1184 data.writeInt( modifier ) ;
1186 if (DEBUG_SVUID)
1187 msg( "\twriteUTF( \"" + desc+ "\" )" ) ;
1188 data.writeUTF(desc);
1189 }
1191 /* Include in the hash all methods except those that are
1192 * private transient and private static.
1193 */
1194 MethodSignature[] methods =
1195 MethodSignature.removePrivateAndSort(method);
1196 for (int i = 0; i < methods.length; i++ ) {
1197 MethodSignature m = methods[i];
1198 String desc = m.signature;
1199 desc = desc.replace('/', '.');
1201 if (DEBUG_SVUID)
1202 msg( "\twriteUTF( \"" + m.member.getName()+ "\" )" ) ;
1203 data.writeUTF(m.member.getName());
1205 // mask out post-1.4 modifiers
1206 int modifier = m.member.getModifiers() & METHOD_MASK ;
1208 if (DEBUG_SVUID)
1209 msg( "\twriteInt( " + modifier + " ) " ) ;
1210 data.writeInt( modifier ) ;
1212 if (DEBUG_SVUID)
1213 msg( "\twriteUTF( \"" + desc + "\" )" ) ;
1214 data.writeUTF(desc);
1215 }
1217 /* Compute the hash value for this class.
1218 * Use only the first 64 bits of the hash.
1219 */
1220 data.flush();
1221 byte hasharray[] = md.digest();
1222 for (int i = 0; i < Math.min(8, hasharray.length); i++) {
1223 h += (long)(hasharray[i] & 255) << (i * 8);
1224 }
1225 } catch (IOException ignore) {
1226 /* can't happen, but be deterministic anyway. */
1227 h = -1;
1228 } catch (NoSuchAlgorithmException complain) {
1229 SecurityException se = new SecurityException() ;
1230 se.initCause( complain ) ;
1231 throw se ;
1232 }
1234 return h;
1235 }
1237 private static long computeStructuralUID(com.sun.corba.se.impl.io.ObjectStreamClass osc, Class<?> cl) {
1238 ByteArrayOutputStream devnull = new ByteArrayOutputStream(512);
1240 long h = 0;
1241 try {
1243 if ((!java.io.Serializable.class.isAssignableFrom(cl)) ||
1244 (cl.isInterface())){
1245 return 0;
1246 }
1248 if (java.io.Externalizable.class.isAssignableFrom(cl)) {
1249 return 1;
1250 }
1252 MessageDigest md = MessageDigest.getInstance("SHA");
1253 DigestOutputStream mdo = new DigestOutputStream(devnull, md);
1254 DataOutputStream data = new DataOutputStream(mdo);
1256 // Get SUID of parent
1257 Class<?> parent = cl.getSuperclass();
1258 if ((parent != null))
1259 // SerialBug 1; acc. to spec the one for
1260 // java.lang.object
1261 // should be computed and put
1262 // && (parent != java.lang.Object.class))
1263 {
1264 //data.writeLong(computeSerialVersionUID(null,parent));
1265 data.writeLong(computeStructuralUID(lookup(parent), parent));
1266 }
1268 if (osc.hasWriteObject())
1269 data.writeInt(2);
1270 else
1271 data.writeInt(1);
1273 // CORBA formal 00-11-03 10.6.2: For each field of the
1274 // class that is mapped to IDL, sorted lexicographically
1275 // by Java field name, in increasing order...
1276 ObjectStreamField[] field = osc.getFields();
1277 if (field.length > 1) {
1278 Arrays.sort(field, compareObjStrFieldsByName);
1279 }
1281 // ...Java field name in UTF encoding, field
1282 // descriptor, as defined by the JVM spec...
1283 for (int i = 0; i < field.length; i++) {
1284 data.writeUTF(field[i].getName());
1285 data.writeUTF(field[i].getSignature());
1286 }
1288 /* Compute the hash value for this class.
1289 * Use only the first 64 bits of the hash.
1290 */
1291 data.flush();
1292 byte hasharray[] = md.digest();
1293 // int minimum = Math.min(8, hasharray.length);
1294 // SerialBug 3: SHA computation is wrong; for loop reversed
1295 //for (int i = minimum; i > 0; i--)
1296 for (int i = 0; i < Math.min(8, hasharray.length); i++) {
1297 h += (long)(hasharray[i] & 255) << (i * 8);
1298 }
1299 } catch (IOException ignore) {
1300 /* can't happen, but be deterministic anyway. */
1301 h = -1;
1302 } catch (NoSuchAlgorithmException complain) {
1303 SecurityException se = new SecurityException();
1304 se.initCause( complain ) ;
1305 throw se ;
1306 }
1307 return h;
1308 }
1310 /**
1311 * Compute the JVM signature for the class.
1312 */
1313 static String getSignature(Class<?> clazz) {
1314 String type = null;
1315 if (clazz.isArray()) {
1316 Class<?> cl = clazz;
1317 int dimensions = 0;
1318 while (cl.isArray()) {
1319 dimensions++;
1320 cl = cl.getComponentType();
1321 }
1322 StringBuffer sb = new StringBuffer();
1323 for (int i = 0; i < dimensions; i++) {
1324 sb.append("[");
1325 }
1326 sb.append(getSignature(cl));
1327 type = sb.toString();
1328 } else if (clazz.isPrimitive()) {
1329 if (clazz == Integer.TYPE) {
1330 type = "I";
1331 } else if (clazz == Byte.TYPE) {
1332 type = "B";
1333 } else if (clazz == Long.TYPE) {
1334 type = "J";
1335 } else if (clazz == Float.TYPE) {
1336 type = "F";
1337 } else if (clazz == Double.TYPE) {
1338 type = "D";
1339 } else if (clazz == Short.TYPE) {
1340 type = "S";
1341 } else if (clazz == Character.TYPE) {
1342 type = "C";
1343 } else if (clazz == Boolean.TYPE) {
1344 type = "Z";
1345 } else if (clazz == Void.TYPE) {
1346 type = "V";
1347 }
1348 } else {
1349 type = "L" + clazz.getName().replace('.', '/') + ";";
1350 }
1351 return type;
1352 }
1354 /*
1355 * Compute the JVM method descriptor for the method.
1356 */
1357 static String getSignature(Method meth) {
1358 StringBuffer sb = new StringBuffer();
1360 sb.append("(");
1362 Class<?>[] params = meth.getParameterTypes(); // avoid clone
1363 for (int j = 0; j < params.length; j++) {
1364 sb.append(getSignature(params[j]));
1365 }
1366 sb.append(")");
1367 sb.append(getSignature(meth.getReturnType()));
1368 return sb.toString();
1369 }
1371 /*
1372 * Compute the JVM constructor descriptor for the constructor.
1373 */
1374 static String getSignature(Constructor cons) {
1375 StringBuffer sb = new StringBuffer();
1377 sb.append("(");
1379 Class<?>[] params = cons.getParameterTypes(); // avoid clone
1380 for (int j = 0; j < params.length; j++) {
1381 sb.append(getSignature(params[j]));
1382 }
1383 sb.append(")V");
1384 return sb.toString();
1385 }
1387 /*
1388 * Cache of Class -> ClassDescriptor Mappings.
1389 */
1390 static private ObjectStreamClassEntry[] descriptorFor = new ObjectStreamClassEntry[61];
1392 /*
1393 * findDescriptorFor a Class. This looks in the cache for a
1394 * mapping from Class -> ObjectStreamClass mappings. The hashCode
1395 * of the Class is used for the lookup since the Class is the key.
1396 * The entries are extended from java.lang.ref.SoftReference so the
1397 * gc will be able to free them if needed.
1398 */
1399 private static ObjectStreamClass findDescriptorFor(Class<?> cl) {
1401 int hash = cl.hashCode();
1402 int index = (hash & 0x7FFFFFFF) % descriptorFor.length;
1403 ObjectStreamClassEntry e;
1404 ObjectStreamClassEntry prev;
1406 /* Free any initial entries whose refs have been cleared */
1407 while ((e = descriptorFor[index]) != null && e.get() == null) {
1408 descriptorFor[index] = e.next;
1409 }
1411 /* Traverse the chain looking for a descriptor with ofClass == cl.
1412 * unlink entries that are unresolved.
1413 */
1414 prev = e;
1415 while (e != null ) {
1416 ObjectStreamClass desc = (ObjectStreamClass)(e.get());
1417 if (desc == null) {
1418 // This entry has been cleared, unlink it
1419 prev.next = e.next;
1420 } else {
1421 if (desc.ofClass == cl)
1422 return desc;
1423 prev = e;
1424 }
1425 e = e.next;
1426 }
1427 return null;
1428 }
1430 /*
1431 * insertDescriptorFor a Class -> ObjectStreamClass mapping.
1432 */
1433 private static void insertDescriptorFor(ObjectStreamClass desc) {
1434 // Make sure not already present
1435 if (findDescriptorFor(desc.ofClass) != null) {
1436 return;
1437 }
1439 int hash = desc.ofClass.hashCode();
1440 int index = (hash & 0x7FFFFFFF) % descriptorFor.length;
1441 ObjectStreamClassEntry e = new ObjectStreamClassEntry(desc);
1442 e.next = descriptorFor[index];
1443 descriptorFor[index] = e;
1444 }
1446 private static Field[] getDeclaredFields(final Class<?> clz) {
1447 return (Field[]) AccessController.doPrivileged(new PrivilegedAction() {
1448 public Object run() {
1449 return clz.getDeclaredFields();
1450 }
1451 });
1452 }
1455 /*
1456 * The name of this descriptor
1457 */
1458 private String name;
1460 /*
1461 * The descriptor of the supertype.
1462 */
1463 private ObjectStreamClass superclass;
1465 /*
1466 * Flags for Serializable and Externalizable.
1467 */
1468 private boolean serializable;
1469 private boolean externalizable;
1471 /*
1472 * Array of persistent fields of this class, sorted by
1473 * type and name.
1474 */
1475 private ObjectStreamField[] fields;
1477 /*
1478 * Class that is a descriptor for in this virtual machine.
1479 */
1480 private Class<?> ofClass;
1482 /*
1483 * True if descriptor for a proxy class.
1484 */
1485 boolean forProxyClass;
1488 /*
1489 * SerialVersionUID for this class.
1490 */
1491 private long suid = kDefaultUID;
1492 private String suidStr = null;
1494 /*
1495 * Actual (computed) SerialVersionUID for this class.
1496 */
1497 private long actualSuid = kDefaultUID;
1498 private String actualSuidStr = null;
1500 /*
1501 * The total number of bytes of primitive fields.
1502 * The total number of object fields.
1503 */
1504 int primBytes;
1505 int objFields;
1507 /**
1508 * Flag indicating whether or not this instance has
1509 * successfully completed initialization. This is to
1510 * try to fix bug 4373844. Working to move to
1511 * reusing java.io.ObjectStreamClass for JDK 1.5.
1512 */
1513 private boolean initialized = false;
1515 /* Internal lock object. */
1516 private Object lock = new Object();
1518 /* In JDK 1.1, external data was not written in block mode.
1519 * As of JDK 1.2, external data is written in block data mode. This
1520 * flag enables JDK 1.2 to be able to read JDK 1.1 written external data.
1521 *
1522 * @since JDK 1.2
1523 */
1524 private boolean hasExternalizableBlockData;
1525 Method writeObjectMethod;
1526 Method readObjectMethod;
1527 private transient Method writeReplaceObjectMethod;
1528 private transient Method readResolveObjectMethod;
1529 private Constructor cons ;
1531 /**
1532 * Beginning in Java to IDL ptc/02-01-12, RMI-IIOP has a
1533 * stream format version 2 which puts a fake valuetype around
1534 * a Serializable's optional custom data. This valuetype has
1535 * a special repository ID made from the Serializable's
1536 * information which we are pre-computing and
1537 * storing here.
1538 */
1539 private String rmiiiopOptionalDataRepId = null;
1541 /*
1542 * ObjectStreamClass that this one was built from.
1543 */
1544 private ObjectStreamClass localClassDesc;
1546 /* Find out if the class has a static class initializer <clinit> */
1547 private static Method hasStaticInitializerMethod = null;
1548 /**
1549 * Returns true if the given class defines a static initializer method,
1550 * false otherwise.
1551 */
1552 private static boolean hasStaticInitializer(Class<?> cl) {
1553 if (hasStaticInitializerMethod == null) {
1554 Class<?> classWithThisMethod = null;
1556 try {
1557 if (classWithThisMethod == null)
1558 classWithThisMethod = java.io.ObjectStreamClass.class;
1560 hasStaticInitializerMethod =
1561 classWithThisMethod.getDeclaredMethod("hasStaticInitializer",
1562 new Class<?>[] { Class.class });
1563 } catch (NoSuchMethodException ex) {
1564 }
1566 if (hasStaticInitializerMethod == null) {
1567 // XXX I18N, logging needed
1568 throw new InternalError("Can't find hasStaticInitializer method on "
1569 + classWithThisMethod.getName());
1570 }
1571 hasStaticInitializerMethod.setAccessible(true);
1572 }
1574 try {
1575 Boolean retval = (Boolean)
1576 hasStaticInitializerMethod.invoke(null, new Object[] { cl });
1577 return retval.booleanValue();
1578 } catch (Exception ex) {
1579 // XXX I18N, logging needed
1580 InternalError ie = new InternalError( "Error invoking hasStaticInitializer" ) ;
1581 ie.initCause( ex ) ;
1582 throw ie ;
1583 }
1584 }
1587 /** use serialVersionUID from JDK 1.1. for interoperability */
1588 private static final long serialVersionUID = -6120832682080437368L;
1590 /**
1591 * Set serialPersistentFields of a Serializable class to this value to
1592 * denote that the class has no Serializable fields.
1593 */
1594 public static final ObjectStreamField[] NO_FIELDS =
1595 new ObjectStreamField[0];
1597 /*
1598 * Entries held in the Cache of known ObjectStreamClass objects.
1599 * Entries are chained together with the same hash value (modulo array size).
1600 */
1601 private static class ObjectStreamClassEntry // extends java.lang.ref.SoftReference
1602 {
1603 ObjectStreamClassEntry(ObjectStreamClass c) {
1604 //super(c);
1605 this.c = c;
1606 }
1607 ObjectStreamClassEntry next;
1609 public Object get()
1610 {
1611 return c;
1612 }
1613 private ObjectStreamClass c;
1614 }
1616 /*
1617 * Comparator object for Classes and Interfaces
1618 */
1619 private static Comparator compareClassByName =
1620 new CompareClassByName();
1622 private static class CompareClassByName implements Comparator {
1623 public int compare(Object o1, Object o2) {
1624 Class<?> c1 = (Class)o1;
1625 Class<?> c2 = (Class)o2;
1626 return (c1.getName()).compareTo(c2.getName());
1627 }
1628 }
1630 /**
1631 * Comparator for ObjectStreamFields by name
1632 */
1633 private final static Comparator compareObjStrFieldsByName
1634 = new CompareObjStrFieldsByName();
1636 private static class CompareObjStrFieldsByName implements Comparator {
1637 public int compare(Object o1, Object o2) {
1638 ObjectStreamField osf1 = (ObjectStreamField)o1;
1639 ObjectStreamField osf2 = (ObjectStreamField)o2;
1641 return osf1.getName().compareTo(osf2.getName());
1642 }
1643 }
1645 /*
1646 * Comparator object for Members, Fields, and Methods
1647 */
1648 private static Comparator compareMemberByName =
1649 new CompareMemberByName();
1651 private static class CompareMemberByName implements Comparator {
1652 public int compare(Object o1, Object o2) {
1653 String s1 = ((Member)o1).getName();
1654 String s2 = ((Member)o2).getName();
1656 if (o1 instanceof Method) {
1657 s1 += getSignature((Method)o1);
1658 s2 += getSignature((Method)o2);
1659 } else if (o1 instanceof Constructor) {
1660 s1 += getSignature((Constructor)o1);
1661 s2 += getSignature((Constructor)o2);
1662 }
1663 return s1.compareTo(s2);
1664 }
1665 }
1667 /* It is expensive to recompute a method or constructor signature
1668 many times, so compute it only once using this data structure. */
1669 private static class MethodSignature implements Comparator {
1670 Member member;
1671 String signature; // cached parameter signature
1673 /* Given an array of Method or Constructor members,
1674 return a sorted array of the non-private members.*/
1675 /* A better implementation would be to implement the returned data
1676 structure as an insertion sorted link list.*/
1677 static MethodSignature[] removePrivateAndSort(Member[] m) {
1678 int numNonPrivate = 0;
1679 for (int i = 0; i < m.length; i++) {
1680 if (! Modifier.isPrivate(m[i].getModifiers())) {
1681 numNonPrivate++;
1682 }
1683 }
1684 MethodSignature[] cm = new MethodSignature[numNonPrivate];
1685 int cmi = 0;
1686 for (int i = 0; i < m.length; i++) {
1687 if (! Modifier.isPrivate(m[i].getModifiers())) {
1688 cm[cmi] = new MethodSignature(m[i]);
1689 cmi++;
1690 }
1691 }
1692 if (cmi > 0)
1693 Arrays.sort(cm, cm[0]);
1694 return cm;
1695 }
1697 /* Assumes that o1 and o2 are either both methods
1698 or both constructors.*/
1699 public int compare(Object o1, Object o2) {
1700 /* Arrays.sort calls compare when o1 and o2 are equal.*/
1701 if (o1 == o2)
1702 return 0;
1704 MethodSignature c1 = (MethodSignature)o1;
1705 MethodSignature c2 = (MethodSignature)o2;
1707 int result;
1708 if (isConstructor()) {
1709 result = c1.signature.compareTo(c2.signature);
1710 } else { // is a Method.
1711 result = c1.member.getName().compareTo(c2.member.getName());
1712 if (result == 0)
1713 result = c1.signature.compareTo(c2.signature);
1714 }
1715 return result;
1716 }
1718 final private boolean isConstructor() {
1719 return member instanceof Constructor;
1720 }
1721 private MethodSignature(Member m) {
1722 member = m;
1723 if (isConstructor()) {
1724 signature = ObjectStreamClass.getSignature((Constructor)m);
1725 } else {
1726 signature = ObjectStreamClass.getSignature((Method)m);
1727 }
1728 }
1729 }
1731 /**
1732 * Returns non-static, non-abstract method with given signature provided it
1733 * is defined by or accessible (via inheritance) by the given class, or
1734 * null if no match found. Access checks are disabled on the returned
1735 * method (if any).
1736 *
1737 * Copied from the Merlin java.io.ObjectStreamClass.
1738 */
1739 private static Method getInheritableMethod(Class<?> cl, String name,
1740 Class<?>[] argTypes,
1741 Class<?> returnType)
1742 {
1743 Method meth = null;
1744 Class<?> defCl = cl;
1745 while (defCl != null) {
1746 try {
1747 meth = defCl.getDeclaredMethod(name, argTypes);
1748 break;
1749 } catch (NoSuchMethodException ex) {
1750 defCl = defCl.getSuperclass();
1751 }
1752 }
1754 if ((meth == null) || (meth.getReturnType() != returnType)) {
1755 return null;
1756 }
1757 meth.setAccessible(true);
1758 int mods = meth.getModifiers();
1759 if ((mods & (Modifier.STATIC | Modifier.ABSTRACT)) != 0) {
1760 return null;
1761 } else if ((mods & (Modifier.PUBLIC | Modifier.PROTECTED)) != 0) {
1762 return meth;
1763 } else if ((mods & Modifier.PRIVATE) != 0) {
1764 return (cl == defCl) ? meth : null;
1765 } else {
1766 return packageEquals(cl, defCl) ? meth : null;
1767 }
1768 }
1770 /**
1771 * Returns true if classes are defined in the same package, false
1772 * otherwise.
1773 *
1774 * Copied from the Merlin java.io.ObjectStreamClass.
1775 */
1776 private static boolean packageEquals(Class<?> cl1, Class<?> cl2) {
1777 Package pkg1 = cl1.getPackage(), pkg2 = cl2.getPackage();
1778 return ((pkg1 == pkg2) || ((pkg1 != null) && (pkg1.equals(pkg2))));
1779 }
1780 }