Source Code Cross Referenced for ObjectOutputStream.java in  » Apache-Harmony-Java-SE » java-package » java » io » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Apache Harmony Java SE » java package » java.io 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         *  Licensed to the Apache Software Foundation (ASF) under one or more
0003:         *  contributor license agreements.  See the NOTICE file distributed with
0004:         *  this work for additional information regarding copyright ownership.
0005:         *  The ASF licenses this file to You under the Apache License, Version 2.0
0006:         *  (the "License"); you may not use this file except in compliance with
0007:         *  the License.  You may obtain a copy of the License at
0008:         *
0009:         *     http://www.apache.org/licenses/LICENSE-2.0
0010:         *
0011:         *  Unless required by applicable law or agreed to in writing, software
0012:         *  distributed under the License is distributed on an "AS IS" BASIS,
0013:         *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014:         *  See the License for the specific language governing permissions and
0015:         *  limitations under the License.
0016:         */
0017:
0018:        package java.io;
0019:
0020:        import java.lang.reflect.InvocationTargetException;
0021:        import java.lang.reflect.Method;
0022:        import java.lang.reflect.Proxy;
0023:        import java.util.IdentityHashMap;
0024:
0025:        import org.apache.harmony.luni.util.Msg;
0026:
0027:        /**
0028:         * An ObjectOutputStream can be used to save Java objects into a stream where
0029:         * the objects can be loaded later with an ObjectInputStream. Primitive data
0030:         * (ints, bytes, chars, etc) can also be saved.
0031:         * 
0032:         * @see ObjectInputStream
0033:         * @see ObjectOutput
0034:         * @see Serializable
0035:         * @see Externalizable
0036:         */
0037:        public class ObjectOutputStream extends OutputStream implements 
0038:                ObjectOutput, ObjectStreamConstants {
0039:
0040:            /*
0041:             * Mask to zero SC_BLOC_DATA bit.
0042:             */
0043:            private static final byte NOT_SC_BLOCK_DATA = (byte) (SC_BLOCK_DATA ^ 0xFF);
0044:
0045:            /*
0046:             * How many nested levels to writeObject. We may not need this.
0047:             */
0048:            private int nestedLevels;
0049:
0050:            /*
0051:             * Where we write to
0052:             */
0053:            private DataOutputStream output;
0054:
0055:            /*
0056:             * If object replacement is enabled or not
0057:             */
0058:            private boolean enableReplace;
0059:
0060:            /*
0061:             * Where we write primitive types to
0062:             */
0063:            private DataOutputStream primitiveTypes;
0064:
0065:            /*
0066:             * Where the write primitive types are actually written to
0067:             */
0068:            private ByteArrayOutputStream primitiveTypesBuffer;
0069:
0070:            /*
0071:             * Table mapping Object -> Integer (handle)
0072:             */
0073:            private IdentityHashMap<Object, Integer> objectsWritten;
0074:
0075:            /*
0076:             * All objects are assigned an ID (integer handle)
0077:             */
0078:            private int currentHandle;
0079:
0080:            /*
0081:             * Used by defaultWriteObject
0082:             */
0083:            private Object currentObject;
0084:
0085:            /*
0086:             * Used by defaultWriteObject
0087:             */
0088:            private ObjectStreamClass currentClass;
0089:
0090:            /*
0091:             * Either ObjectStreamConstants.PROTOCOL_VERSION_1 or
0092:             * ObjectStreamConstants.PROTOCOL_VERSION_2
0093:             */
0094:            private int protocolVersion;
0095:
0096:            /*
0097:             * Used to detect nested exception when saving an exception due to an error
0098:             */
0099:            private StreamCorruptedException nestedException;
0100:
0101:            /*
0102:             * Used to keep track of the PutField object for the class/object being
0103:             * written
0104:             */
0105:            private EmulatedFieldsForDumping currentPutField;
0106:
0107:            /*
0108:             * Allows the receiver to decide if it needs to call writeObjectOverride
0109:             */
0110:            private boolean subclassOverridingImplementation;
0111:
0112:            /**
0113:             * Inner class to provide access to serializable fields
0114:             */
0115:            public static abstract class PutField {
0116:                public abstract void put(String name, boolean value);
0117:
0118:                public abstract void put(String name, char value);
0119:
0120:                public abstract void put(String name, byte value);
0121:
0122:                public abstract void put(String name, short value);
0123:
0124:                public abstract void put(String name, int value);
0125:
0126:                public abstract void put(String name, long value);
0127:
0128:                public abstract void put(String name, float value);
0129:
0130:                public abstract void put(String name, double value);
0131:
0132:                public abstract void put(String name, Object value);
0133:
0134:                /**
0135:                 * @deprecated This method is unsafe and may corrupt the output stream.
0136:                 *             Use ObjectOutputStream#writeFields() instead.
0137:                 */
0138:                @Deprecated
0139:                public abstract void write(ObjectOutput out) throws IOException;
0140:            }
0141:
0142:            /**
0143:             * Constructs a new <code>ObjectOutputStream</code>. The representation
0144:             * and proper initialization is in the hands of subclasses.
0145:             * 
0146:             * @throws IOException
0147:             * @throws SecurityException
0148:             *             if subclassing this is not allowed
0149:             * 
0150:             * @see SecurityManager#checkPermission(java.security.Permission)
0151:             */
0152:            protected ObjectOutputStream() throws IOException,
0153:                    SecurityException {
0154:                super ();
0155:                SecurityManager currentManager = System.getSecurityManager();
0156:                if (currentManager != null) {
0157:                    currentManager
0158:                            .checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
0159:                }
0160:                /*
0161:                 * WARNING - we should throw IOException if not called from a subclass
0162:                 * according to the JavaDoc. Add the test.
0163:                 */
0164:                this .subclassOverridingImplementation = true;
0165:            }
0166:
0167:            /**
0168:             * Constructs a new ObjectOutputStream on the OutputStream
0169:             * <code>output</code>. All writes are now filtered through this stream.
0170:             * 
0171:             * @param output
0172:             *            The non-null OutputStream to filter writes on.
0173:             * 
0174:             * @throws IOException
0175:             *             If an IO exception happened when writing the object stream
0176:             *             header
0177:             */
0178:            public ObjectOutputStream(OutputStream output) throws IOException {
0179:                Class<?> implementationClass = getClass();
0180:                Class<?> this Class = ObjectOutputStream.class;
0181:                if (implementationClass != this Class) {
0182:                    boolean mustCheck = false;
0183:                    try {
0184:                        Method method = implementationClass
0185:                                .getMethod(
0186:                                        "putFields", //$NON-NLS-1$
0187:                                        ObjectStreamClass.EMPTY_CONSTRUCTOR_PARAM_TYPES);
0188:                        mustCheck = method.getDeclaringClass() != this Class;
0189:                    } catch (NoSuchMethodException e) {
0190:                    }
0191:                    if (!mustCheck) {
0192:                        try {
0193:                            Method method = implementationClass.getMethod(
0194:                                    "writeUnshared", //$NON-NLS-1$
0195:                                    ObjectStreamClass.UNSHARED_PARAM_TYPES);
0196:                            mustCheck = method.getDeclaringClass() != this Class;
0197:                        } catch (NoSuchMethodException e) {
0198:                        }
0199:                    }
0200:                    if (mustCheck) {
0201:                        SecurityManager sm = System.getSecurityManager();
0202:                        if (sm != null) {
0203:                            sm
0204:                                    .checkPermission(ObjectStreamConstants.SUBCLASS_IMPLEMENTATION_PERMISSION);
0205:                        }
0206:                    }
0207:                }
0208:                this .output = (output instanceof  DataOutputStream) ? (DataOutputStream) output
0209:                        : new DataOutputStream(output);
0210:                this .enableReplace = false;
0211:                this .protocolVersion = PROTOCOL_VERSION_2;
0212:                this .subclassOverridingImplementation = false;
0213:
0214:                resetState();
0215:                this .nestedException = new StreamCorruptedException();
0216:                // So write...() methods can be used by
0217:                // subclasses during writeStreamHeader()
0218:                primitiveTypes = this .output;
0219:                // Has to be done here according to the specification
0220:                writeStreamHeader();
0221:                primitiveTypes = null;
0222:            }
0223:
0224:            /**
0225:             * Writes optional information for class <code>aClass</code> into the
0226:             * stream represented by the receiver. This optional data can be read when
0227:             * deserializing the class descriptor (ObjectStreamClass) for this class
0228:             * from the input stream. By default no extra data is saved.
0229:             * 
0230:             * @param aClass
0231:             *            The class to annotate
0232:             * 
0233:             * @throws IOException
0234:             *             If an IO exception happened when annotating the class.
0235:             * 
0236:             * @see ObjectInputStream#resolveClass
0237:             */
0238:            protected void annotateClass(Class<?> aClass) throws IOException {
0239:                // By default no extra info is saved. Subclasses can override
0240:            }
0241:
0242:            /**
0243:             * Writes optional information for a proxy class into the stream represented
0244:             * by the receiver. This optional data can be read when deserializing the
0245:             * proxy class from the input stream. By default no extra data is saved.
0246:             * 
0247:             * @param aClass
0248:             *            The proxy class to annotate
0249:             * 
0250:             * @throws IOException
0251:             *             If an IO exception happened when annotating the class.
0252:             * 
0253:             * @see ObjectInputStream#resolveProxyClass
0254:             */
0255:            protected void annotateProxyClass(Class<?> aClass)
0256:                    throws IOException {
0257:                // By default no extra info is saved. Subclasses can override
0258:            }
0259:
0260:            /**
0261:             * Do the necessary work to see if the receiver can be used to write
0262:             * primitive types like int, char, etc.
0263:             */
0264:            private void checkWritePrimitiveTypes() {
0265:                if (primitiveTypes == null) {
0266:                    // If we got here we have no Stream previously created
0267:                    // WARNING - if the stream does not grow, this code is wrong
0268:                    primitiveTypesBuffer = new ByteArrayOutputStream(128);
0269:                    primitiveTypes = new DataOutputStream(primitiveTypesBuffer);
0270:                }
0271:            }
0272:
0273:            /**
0274:             * Close this ObjectOutputStream. Any buffered data is flushed. This
0275:             * implementation closes the target stream.
0276:             * 
0277:             * @throws IOException
0278:             *             If an error occurs attempting to close this stream.
0279:             */
0280:            @Override
0281:            public void close() throws IOException {
0282:                // First flush what is needed (primitive data, etc)
0283:                flush();
0284:                output.close();
0285:            }
0286:
0287:            /**
0288:             * Computes the collection of emulated fields that users can manipulate to
0289:             * store a representation different than the one declared by the class of
0290:             * the object being dumped.
0291:             * 
0292:             * @see #writeFields
0293:             * @see #writeFieldValues(EmulatedFieldsForDumping)
0294:             */
0295:            private void computePutField() {
0296:                currentPutField = new EmulatedFieldsForDumping(currentClass);
0297:            }
0298:
0299:            /**
0300:             * Default method to write objects into the receiver. Fields defined in the
0301:             * object's class and superclasses (which are Serializable) will be saved.
0302:             * 
0303:             * @throws IOException
0304:             *             If an IO error occurs attempting to write the object data
0305:             * 
0306:             * @see ObjectInputStream#defaultReadObject
0307:             */
0308:            public void defaultWriteObject() throws IOException {
0309:                // We can't be called from just anywhere. There are rules.
0310:                if (currentObject == null) {
0311:                    throw new NotActiveException();
0312:                }
0313:                writeFieldValues(currentObject, currentClass);
0314:            }
0315:
0316:            /**
0317:             * Flushes buffered primitive data into the receiver.
0318:             * 
0319:             * @throws IOException
0320:             *             If an error occurs attempting to drain the data
0321:             */
0322:            protected void drain() throws IOException {
0323:                if (primitiveTypes == null || primitiveTypesBuffer == null) {
0324:                    return;
0325:                }
0326:
0327:                // If we got here we have a Stream previously created
0328:                int offset = 0;
0329:                byte[] written = primitiveTypesBuffer.toByteArray();
0330:                // Normalize the primitive data
0331:                while (offset < written.length) {
0332:                    int toWrite = written.length - offset > 1024 ? 1024
0333:                            : written.length - offset;
0334:                    if (toWrite < 256) {
0335:                        output.writeByte(TC_BLOCKDATA);
0336:                        output.writeByte((byte) toWrite);
0337:                    } else {
0338:                        output.writeByte(TC_BLOCKDATALONG);
0339:                        output.writeInt(toWrite);
0340:                    }
0341:
0342:                    // write primitive types we had and the marker of end-of-buffer
0343:                    output.write(written, offset, toWrite);
0344:                    offset += toWrite;
0345:                }
0346:
0347:                // and now we're clean to a state where we can write an object
0348:                primitiveTypes = null;
0349:                primitiveTypesBuffer = null;
0350:            }
0351:
0352:            /**
0353:             * Dumps the parameter <code>obj</code> only if it is <code>null</code>
0354:             * or an object that has already been dumped previously.
0355:             * 
0356:             * @param obj
0357:             *            Object to check if an instance previously dumped by this
0358:             *            stream.
0359:             * @return null if it is an instance which has not been dumped yet (and this
0360:             *         method does nothing). Integer, if <code>obj</code> is an
0361:             *         instance which has been dumped already. In this case this method
0362:             *         saves the cyclic reference.
0363:             * 
0364:             * @throws IOException
0365:             *             If an error occurs attempting to save <code>null</code> or
0366:             *             a cyclic reference.
0367:             */
0368:            private Integer dumpCycle(Object obj) throws IOException {
0369:                // If the object has been saved already, save its handle only
0370:                Integer handle = registeredObjectHandleFor(obj);
0371:                if (handle != null) {
0372:                    writeCyclicReference(handle);
0373:                    return handle;
0374:                }
0375:                return null;
0376:            }
0377:
0378:            /**
0379:             * Enables/disables object replacement for the receiver. By default this is
0380:             * not enabled. Only trusted subclasses (loaded with system class loader)
0381:             * can override this behavior.
0382:             * 
0383:             * @param enable
0384:             *            if true, enables replacement. If false, disables replacement.
0385:             * @return boolean the previous configuration (if it was enabled or
0386:             *         disabled)
0387:             * 
0388:             * @throws SecurityException
0389:             *             If the class of the receiver is not trusted
0390:             * 
0391:             * @see #replaceObject
0392:             * @see ObjectInputStream#enableResolveObject
0393:             */
0394:            protected boolean enableReplaceObject(boolean enable)
0395:                    throws SecurityException {
0396:                if (enable) {
0397:                    // The Stream has to be trusted for this feature to be enabled.
0398:                    // trusted means the stream's classloader has to be null
0399:                    SecurityManager currentManager = System
0400:                            .getSecurityManager();
0401:                    if (currentManager != null) {
0402:                        currentManager.checkPermission(SUBSTITUTION_PERMISSION);
0403:                    }
0404:                }
0405:                boolean originalValue = enableReplace;
0406:                enableReplace = enable;
0407:                return originalValue;
0408:            }
0409:
0410:            /**
0411:             * Flush this ObjectOutputStream. Any pending writes to the underlying
0412:             * stream are written out when this method is invoked.
0413:             * 
0414:             * @throws IOException
0415:             *             If an error occurs attempting to flush this
0416:             *             ObjectOutputStream.
0417:             */
0418:            @Override
0419:            public void flush() throws IOException {
0420:                drain();
0421:                output.flush();
0422:            }
0423:
0424:            /**
0425:             * Get the value of field named
0426:             * <code>fieldName<code> of object <code>instance</code>. The
0427:             * field is declared by class <code>declaringClass</code>. The field is supposed to be
0428:             * a boolean.
0429:             *
0430:             * This method could be implemented non-natively on top of java.lang.reflect implementations
0431:             * that support the <code>setAccessible</code> API, at the expense of extra object creation
0432:             * (java.lang.reflect.Field). Otherwise Serialization could not fetch private fields, except
0433:             * by the use of a native method like this one.
0434:             *
0435:             * @param		instance		Object whose field value we want to fetch
0436:             * @param		declaringClass	The class that declares the field
0437:             * @param		fieldName		Name of the field we want to fetch
0438:             * @return		the value of the field
0439:             *
0440:             * @throws		NoSuchFieldError If the field does not exist.
0441:             */
0442:            private static native boolean getFieldBool(Object instance,
0443:                    Class<?> declaringClass, String fieldName);
0444:
0445:            /**
0446:             * Get the value of field named
0447:             * <code>fieldName<code> of object <code>instance</code>. The
0448:             * field is declared by class <code>declaringClass</code>. The field is supposed to be
0449:             * a byte
0450:             *
0451:             * This method could be implemented non-natively on top of java.lang.reflect implementations
0452:             * that support the <code>setAccessible</code> API, at the expense of extra object creation
0453:             * (java.lang.reflect.Field). Otherwise Serialization could not fetch private fields, except
0454:             * by the use of a native method like this one.
0455:             *
0456:             * @param		instance		Object whose field value we want to fetch
0457:             * @param		declaringClass	The class that declares the field
0458:             * @param		fieldName		Name of the field we want to fetch
0459:             * @return		the value of the field
0460:             *
0461:             * @throws		NoSuchFieldError If the field does not exist.
0462:             */
0463:            private static native byte getFieldByte(Object instance,
0464:                    Class<?> declaringClass, String fieldName);
0465:
0466:            /**
0467:             * Get the value of field named
0468:             * <code>fieldName<code> of object <code>instance</code>. The
0469:             * field is declared by class <code>declaringClass</code>. The field is supposed to be
0470:             * a char.
0471:             *
0472:             * This method could be implemented non-natively on top of java.lang.reflect implementations
0473:             * that support the <code>setAccessible</code> API, at the expense of extra object creation
0474:             * (java.lang.reflect.Field). Otherwise Serialization could not fetch private fields, except
0475:             * by the use of a native method like this one.
0476:             *
0477:             * @param		instance		Object whose field value we want to fetch
0478:             * @param		declaringClass	The class that declares the field
0479:             * @param		fieldName		Name of the field we want to fetch
0480:             * @return		the value of the field
0481:             *
0482:             * @throws		NoSuchFieldError If the field does not exist.
0483:             */
0484:            private static native char getFieldChar(Object instance,
0485:                    Class<?> declaringClass, String fieldName);
0486:
0487:            /**
0488:             * Get the value of field named
0489:             * <code>fieldName<code> of object <code>instance</code>. The
0490:             * field is declared by class <code>declaringClass</code>. The field is supposed to be
0491:             * a double.
0492:             *
0493:             * This method could be implemented non-natively on top of java.lang.reflect implementations
0494:             * that support the <code>setAccessible</code> API, at the expense of extra object creation
0495:             * (java.lang.reflect.Field). Otherwise Serialization could not fetch private fields, except
0496:             * by the use of a native method like this one.
0497:             *
0498:             * @param		instance		Object whose field value we want to fetch
0499:             * @param		declaringClass	The class that declares the field
0500:             * @param		fieldName		Name of the field we want to fetch
0501:             * @return		the value of the field
0502:             *
0503:             * @throws		NoSuchFieldError If the field does not exist.
0504:             */
0505:            private static native double getFieldDouble(Object instance,
0506:                    Class<?> declaringClass, String fieldName);
0507:
0508:            /**
0509:             * Get the value of field named
0510:             * <code>fieldName<code> of object <code>instance</code>. The
0511:             * field is declared by class <code>declaringClass</code>. The field is supposed to be
0512:             * a float.
0513:             *
0514:             * This method could be implemented non-natively on top of java.lang.reflect implementations
0515:             * that support the <code>setAccessible</code> API, at the expense of extra object creation
0516:             * (java.lang.reflect.Field). Otherwise Serialization could not fetch private fields, except
0517:             * by the use of a native method like this one.
0518:             *
0519:             * @param		instance		Object whose field value we want to fetch
0520:             * @param		declaringClass	The class that declares the field
0521:             * @param		fieldName		Name of the field we want to fetch
0522:             * @return		the value of the field
0523:             *
0524:             * @throws		NoSuchFieldError If the field does not exist.
0525:             */
0526:            private static native float getFieldFloat(Object instance,
0527:                    Class<?> declaringClass, String fieldName);
0528:
0529:            /**
0530:             * Get the value of field named
0531:             * <code>fieldName<code> of object <code>instance</code>. The
0532:             * field is declared by class <code>declaringClass</code>. The field is supposed to be
0533:             * an int.
0534:             *
0535:             * This method could be implemented non-natively on top of java.lang.reflect implementations
0536:             * that support the <code>setAccessible</code> API, at the expense of extra object creation
0537:             * (java.lang.reflect.Field). Otherwise Serialization could not fetch private fields, except
0538:             * by the use of a native method like this one.
0539:             *
0540:             * @param		instance		Object whose field value we want to fetch
0541:             * @param		declaringClass	The class that declares the field
0542:             * @param		fieldName		Name of the field we want to fetch
0543:             * @return		the value of the field
0544:             *
0545:             * @throws		NoSuchFieldError If the field does not exist.
0546:             */
0547:            private static native int getFieldInt(Object instance,
0548:                    Class<?> declaringClass, String fieldName);
0549:
0550:            /**
0551:             * Get the value of field named
0552:             * <code>fieldName<code> of object <code>instance</code>. The
0553:             * field is declared by class <code>declaringClass</code>. The field is supposed to be
0554:             * a long.
0555:             *
0556:             * This method could be implemented non-natively on top of java.lang.reflect implementations
0557:             * that support the <code>setAccessible</code> API, at the expense of extra object creation
0558:             * (java.lang.reflect.Field). Otherwise Serialization could not fetch private fields, except
0559:             * by the use of a native method like this one.
0560:             *
0561:             * @param		instance		Object whose field value we want to fetch
0562:             * @param		declaringClass	The class that declares the field
0563:             * @param		fieldName		Name of the field we want to fetch
0564:             * @return		the value of the field
0565:             *
0566:             * @throws		NoSuchFieldError If the field does not exist.
0567:             */
0568:            private static native long getFieldLong(Object instance,
0569:                    Class<?> declaringClass, String fieldName);
0570:
0571:            /**
0572:             * Get the value of field named
0573:             * <code>fieldName<code> of object <code>instance</code>. The
0574:             * field is declared by class <code>declaringClass</code>. The field is supposed to be
0575:             * an Object type whose name is <code>fieldTypeName</code>.
0576:             *
0577:             * This method could be implemented non-natively on top of java.lang.reflect implementations
0578:             * that support the <code>setAccessible</code> API, at the expense of extra object creation
0579:             * (java.lang.reflect.Field). Otherwise Serialization could not fetch private fields, except
0580:             * by the use of a native method like this one.
0581:             *
0582:             * @param		instance		Object whose field value we want to fetch
0583:             * @param		declaringClass	The class that declares the field
0584:             * @param		fieldName		Name of the field we want to fetch
0585:             * @param		fieldTypeName	Name of the class that defines the type of this field
0586:             * @return		the value of the field
0587:             *
0588:             * @throws		NoSuchFieldError If the field does not exist.
0589:             */
0590:            private static native Object getFieldObj(Object instance,
0591:                    Class<?> declaringClass, String fieldName,
0592:                    String fieldTypeName);
0593:
0594:            /**
0595:             * Get the value of field named
0596:             * <code>fieldName<code> of object <code>instance</code>. The
0597:             * field is declared by class <code>declaringClass</code>. The field is supposed to be
0598:             * a short.
0599:             *
0600:             * This method could be implemented non-natively on top of java.lang.reflect implementations
0601:             * that support the <code>setAccessible</code> API, at the expense of extra object creation
0602:             * (java.lang.reflect.Field). Otherwise Serialization could not fetch private fields, except
0603:             * by the use of a native method like this one.
0604:             *
0605:             * @param		instance		Object whose field value we want to fetch
0606:             * @param		declaringClass	The class that declares the field
0607:             * @param		fieldName		Name of the field we want to fetch
0608:             * @return		the value of the field
0609:             *
0610:             * @throws		NoSuchFieldError If the field does not exist.
0611:             */
0612:            private static native short getFieldShort(Object instance,
0613:                    Class<?> declaringClass, String fieldName);
0614:
0615:            /**
0616:             * Return the next <code>int</code> handle to be used to indicate cyclic
0617:             * references being saved to the stream.
0618:             * 
0619:             * @return int, the next handle to represent the next cyclic reference
0620:             */
0621:            private int nextHandle() {
0622:                return this .currentHandle++;
0623:            }
0624:
0625:            /**
0626:             * Return the <code>PutField</code> object for the receiver. This allows
0627:             * users to transfer values from actual object fields in the object being
0628:             * dumped to the emulated fields represented by the <code>PutField</code>
0629:             * returned by this method.
0630:             * 
0631:             * @return the PutFieldObject for the receiver
0632:             * 
0633:             * @throws IOException
0634:             *             If an IO error occurs
0635:             * @throws NotActiveException
0636:             *             If this method is not called from writeObject()
0637:             * 
0638:             * @see ObjectInputStream#defaultReadObject
0639:             */
0640:            public PutField putFields() throws IOException {
0641:                // We can't be called from just anywhere. There are rules.
0642:                if (currentObject == null) {
0643:                    throw new NotActiveException();
0644:                }
0645:                if (currentPutField == null) {
0646:                    computePutField();
0647:                }
0648:                return currentPutField;
0649:            }
0650:
0651:            /**
0652:             * Return the <code>Integer</code> handle used to tag object
0653:             * <code>obj</code> as an instance that has been dumped already. Return
0654:             * <code>null</code> if object <code>obj</code> has not been saved yet.
0655:             * 
0656:             * @param obj
0657:             *            the object
0658:             * @return null if object <code>obj</code> has not been saved yet. Integer
0659:             *         The handle that this object was assigned when it was saved.
0660:             */
0661:            private Integer registeredObjectHandleFor(Object obj) {
0662:                return objectsWritten.get(obj);
0663:            }
0664:
0665:            /**
0666:             * Assume object <code>obj</code> has not been dumped yet, and assign a
0667:             * handle to it
0668:             * 
0669:             * @param obj
0670:             *            Non-null object being dumped.
0671:             * @return the handle that this object is being assigned.
0672:             * 
0673:             * @see #nextHandle
0674:             */
0675:            private Integer registerObjectWritten(Object obj) {
0676:                Integer handle = Integer.valueOf(nextHandle());
0677:                registerObjectWritten(obj, handle);
0678:                return handle;
0679:            }
0680:
0681:            /**
0682:             * Remove the unshared object from the table, and restore any previous
0683:             * handle.
0684:             * 
0685:             * @param obj
0686:             *            Non-null object being dumped.
0687:             * @param previousHandle
0688:             *            The handle of the previous identical object dumped
0689:             */
0690:            private void removeUnsharedReference(Object obj,
0691:                    Integer previousHandle) {
0692:                if (previousHandle != null) {
0693:                    registerObjectWritten(obj, previousHandle);
0694:                } else {
0695:                    objectsWritten.remove(obj);
0696:                }
0697:            }
0698:
0699:            /**
0700:             * Assume object <code>obj</code> has not been dumped yet, and assign a
0701:             * handle to it, <code>handle</code>.
0702:             * 
0703:             * @param obj
0704:             *            Non-null object being dumped.
0705:             * @param handle
0706:             *            An Integer, the handle to this object
0707:             * 
0708:             * @see #nextHandle
0709:             */
0710:            private void registerObjectWritten(Object obj, Integer handle) {
0711:                objectsWritten.put(obj, handle);
0712:            }
0713:
0714:            /**
0715:             * If <code>enableReplaceObject()</code> was activated, computes the
0716:             * replacement object for the original object <code>object</code> and
0717:             * returns the replacement. Otherwise returns <code>object</code>.
0718:             * 
0719:             * @param object
0720:             *            Original object for which a replacement may be defined
0721:             * @return a possibly new, replacement object for <code>object</code>
0722:             * 
0723:             * @throws IOException
0724:             *             If any IO problem occurred when trying to resolve the object.
0725:             * 
0726:             * @see #enableReplaceObject
0727:             * @see ObjectInputStream#enableResolveObject
0728:             * @see ObjectInputStream#resolveObject
0729:             */
0730:            protected Object replaceObject(Object object) throws IOException {
0731:                // By default no object replacement. Subclasses can override
0732:                return object;
0733:            }
0734:
0735:            /**
0736:             * Reset the receiver. A marker is written to the stream, so that
0737:             * deserialization will also perform a rest at the same point. Objects
0738:             * previously written are no longer remembered, so they will be written
0739:             * again (instead of a cyclical reference) if found in the object graph.
0740:             * 
0741:             * @throws IOException
0742:             *             If any IO problem occurred when trying to reset the receiver
0743:             */
0744:            public void reset() throws IOException {
0745:                // First we flush what we have
0746:                drain();
0747:                /*
0748:                 * And dump a reset marker, so that the ObjectInputStream can reset
0749:                 * itself at the same point
0750:                 */
0751:                output.writeByte(TC_RESET);
0752:                // Now we reset ourselves
0753:                resetState();
0754:            }
0755:
0756:            /**
0757:             * Reset the collection of objects already dumped by the receiver. If the
0758:             * objects are found again in the object graph, the receiver will dump them
0759:             * again, instead of a handle (cyclic reference).
0760:             * 
0761:             */
0762:            private void resetSeenObjects() {
0763:                objectsWritten = new IdentityHashMap<Object, Integer>();
0764:                currentHandle = baseWireHandle;
0765:            }
0766:
0767:            /**
0768:             * Reset the receiver. The collection of objects already dumped by the
0769:             * receiver is reset, and internal structures are also reset so that the
0770:             * receiver knows it is in a fresh clean state.
0771:             * 
0772:             */
0773:            private void resetState() {
0774:                resetSeenObjects();
0775:                nestedLevels = 0;
0776:            }
0777:
0778:            /**
0779:             * Set the receiver to use the given protocol version.
0780:             * 
0781:             * @param version
0782:             *            protocol version to be used
0783:             * 
0784:             * @throws IOException
0785:             *             If an IO error occurs
0786:             */
0787:            public void useProtocolVersion(int version) throws IOException {
0788:                if (!objectsWritten.isEmpty()) {
0789:                    // KA028=Cannot set protocol version when stream in use
0790:                    throw new IllegalStateException(Msg.getString("KA028")); //$NON-NLS-1$
0791:                }
0792:                if (version != ObjectStreamConstants.PROTOCOL_VERSION_1
0793:                        && version != ObjectStreamConstants.PROTOCOL_VERSION_2) {
0794:                    // K00b3=Unknown protocol\: {0}
0795:                    throw new IllegalArgumentException(Msg.getString(
0796:                            "K00b3", version)); //$NON-NLS-1$
0797:                }
0798:                protocolVersion = version;
0799:            }
0800:
0801:            /**
0802:             * Writes the entire contents of the byte array <code>buffer</code> to
0803:             * this ObjectOutputStream.
0804:             * 
0805:             * @param buffer
0806:             *            the buffer to be written
0807:             * 
0808:             * @throws IOException
0809:             *             If an error occurs attempting to write to this
0810:             *             ObjectOutputStream.
0811:             */
0812:            @Override
0813:            public void write(byte[] buffer) throws IOException {
0814:                checkWritePrimitiveTypes();
0815:                primitiveTypes.write(buffer);
0816:            }
0817:
0818:            /**
0819:             * Writes <code>length</code> <code>bytes</code> from the byte array
0820:             * <code>buffer</code> starting at offset <code>offset</code> to the
0821:             * ObjectOutputStream.
0822:             * 
0823:             * @param buffer
0824:             *            the buffer to be written
0825:             * @param offset
0826:             *            offset in buffer to get bytes
0827:             * @param length
0828:             *            number of bytes in buffer to write
0829:             * 
0830:             * @throws IOException
0831:             *             If an error occurs attempting to write to this OutputStream.
0832:             */
0833:            @Override
0834:            public void write(byte[] buffer, int offset, int length)
0835:                    throws IOException {
0836:                checkWritePrimitiveTypes();
0837:                primitiveTypes.write(buffer, offset, length);
0838:            }
0839:
0840:            /**
0841:             * Write one byte (<code>value</code>) into the receiver's underlying
0842:             * stream.
0843:             * 
0844:             * @param value
0845:             *            The primitive data to write. Only the lower byte is written.
0846:             * 
0847:             * @throws IOException
0848:             *             If an IO exception happened when writing the byte.
0849:             */
0850:            @Override
0851:            public void write(int value) throws IOException {
0852:                checkWritePrimitiveTypes();
0853:                primitiveTypes.write(value);
0854:            }
0855:
0856:            /**
0857:             * Write primitive data of type boolean (<code>value</code>)into the
0858:             * receiver's underlying stream.
0859:             * 
0860:             * @param value
0861:             *            The primitive data to write
0862:             * 
0863:             * @throws IOException
0864:             *             If an IO exception happened when writing the primitive data.
0865:             */
0866:            public void writeBoolean(boolean value) throws IOException {
0867:                checkWritePrimitiveTypes();
0868:                primitiveTypes.writeBoolean(value);
0869:            }
0870:
0871:            /**
0872:             * Write primitive data of type byte (<code>value</code>)into the
0873:             * receiver's underlying stream.
0874:             * 
0875:             * @param value
0876:             *            The primitive data to write
0877:             * 
0878:             * @throws IOException
0879:             *             If an IO exception happened when writing the primitive data.
0880:             */
0881:            public void writeByte(int value) throws IOException {
0882:                checkWritePrimitiveTypes();
0883:                primitiveTypes.writeByte(value);
0884:            }
0885:
0886:            /**
0887:             * Write a String as a sequence of bytes (only lower-order 8 bits of each
0888:             * char are written), as primitive data (<code>value</code>) into the
0889:             * receiver's underlying stream.
0890:             * 
0891:             * @param value
0892:             *            The primitive data to write
0893:             * 
0894:             * @throws IOException
0895:             *             If an IO exception happened when writing the primitive data.
0896:             */
0897:            public void writeBytes(String value) throws IOException {
0898:                checkWritePrimitiveTypes();
0899:                primitiveTypes.writeBytes(value);
0900:            }
0901:
0902:            /**
0903:             * Write primitive data of type char (<code>value</code>)into the
0904:             * receiver's underlying stream.
0905:             * 
0906:             * @param value
0907:             *            The primitive data to write
0908:             * 
0909:             * @throws IOException
0910:             *             If an IO exception happened when writing the primitive data.
0911:             */
0912:            public void writeChar(int value) throws IOException {
0913:                checkWritePrimitiveTypes();
0914:                primitiveTypes.writeChar(value);
0915:            }
0916:
0917:            /**
0918:             * Write a String as a sequence of char, as primitive data (<code>value</code>)
0919:             * into the receiver's underlying stream.
0920:             * 
0921:             * @param value
0922:             *            The primitive data to write
0923:             * 
0924:             * @throws IOException
0925:             *             If an IO exception happened when writing the primitive data.
0926:             */
0927:            public void writeChars(String value) throws IOException {
0928:                checkWritePrimitiveTypes();
0929:                primitiveTypes.writeChars(value);
0930:            }
0931:
0932:            /**
0933:             * Write a class descriptor <code>classDesc</code> (an
0934:             * <code>ObjectStreamClass</code>) to the stream.
0935:             * 
0936:             * @param classDesc
0937:             *            The class descriptor (an <code>ObjectStreamClass</code>) to
0938:             *            be dumped
0939:             * @param unshared
0940:             *            Write the object unshared
0941:             * @return the handle assigned to the class descriptor
0942:             * 
0943:             * @throws IOException
0944:             *             If an IO exception happened when writing the class
0945:             *             descriptor.
0946:             */
0947:            private Integer writeClassDesc(ObjectStreamClass classDesc,
0948:                    boolean unshared) throws IOException {
0949:                if (classDesc == null) {
0950:                    writeNull();
0951:                    return null;
0952:                }
0953:                Integer handle = null;
0954:                if (!unshared) {
0955:                    handle = dumpCycle(classDesc);
0956:                }
0957:                if (handle == null) {
0958:                    Class<?> classToWrite = classDesc.forClass();
0959:                    Integer previousHandle = objectsWritten.get(classDesc);
0960:                    // If we got here, it is a new (non-null) classDesc that will have
0961:                    // to be registered as well
0962:                    handle = registerObjectWritten(classDesc);
0963:
0964:                    if (Proxy.isProxyClass(classToWrite)) {
0965:                        output.writeByte(TC_PROXYCLASSDESC);
0966:                        Class<?>[] interfaces = classToWrite.getInterfaces();
0967:                        output.writeInt(interfaces.length);
0968:                        for (int i = 0; i < interfaces.length; i++) {
0969:                            output.writeUTF(interfaces[i].getName());
0970:                        }
0971:                        annotateProxyClass(classToWrite);
0972:                        output.writeByte(TC_ENDBLOCKDATA);
0973:                        writeClassDescForClass(Proxy.class);
0974:                        if (unshared) {
0975:                            // remove reference to unshared object
0976:                            removeUnsharedReference(classDesc, previousHandle);
0977:                        }
0978:                        return handle;
0979:                    }
0980:
0981:                    output.writeByte(TC_CLASSDESC);
0982:                    if (protocolVersion == PROTOCOL_VERSION_1) {
0983:                        writeNewClassDesc(classDesc);
0984:                    } else {
0985:                        // So write...() methods can be used by
0986:                        // subclasses during writeClassDescriptor()
0987:                        primitiveTypes = output;
0988:                        writeClassDescriptor(classDesc);
0989:                        primitiveTypes = null;
0990:                    }
0991:                    // Extra class info (optional)
0992:                    annotateClass(classToWrite);
0993:                    drain(); // flush primitive types in the annotation
0994:                    output.writeByte(TC_ENDBLOCKDATA);
0995:                    writeClassDesc(classDesc.getSuperclass(), unshared);
0996:                    if (unshared) {
0997:                        // remove reference to unshared object
0998:                        removeUnsharedReference(classDesc, previousHandle);
0999:                    }
1000:                }
1001:                return handle;
1002:            }
1003:
1004:            /**
1005:             * Writes a class descriptor (an <code>ObjectStreamClass</code>) that
1006:             * corresponds to the <code>java.lang.Class objClass</code> to the stream.
1007:             * 
1008:             * @param objClass
1009:             *            The class for which a class descriptor (an
1010:             *            <code>ObjectStreamClass</code>) will be dumped.
1011:             * @return the handle assigned to the class descriptor
1012:             * 
1013:             * @throws IOException
1014:             *             If an IO exception happened when writing the class
1015:             *             descriptor.
1016:             * 
1017:             */
1018:            private Integer writeClassDescForClass(Class<?> objClass)
1019:                    throws IOException {
1020:                return writeClassDesc(ObjectStreamClass.lookup(objClass), false);
1021:            }
1022:
1023:            /**
1024:             * Writes a handle representing a cyclic reference (object previously
1025:             * dumped).
1026:             * 
1027:             * @param handle
1028:             *            The Integer handle that represents an object previously seen
1029:             * 
1030:             * @throws IOException
1031:             *             If an IO exception happened when writing the cyclic
1032:             *             reference.
1033:             */
1034:            private void writeCyclicReference(Integer handle)
1035:                    throws IOException {
1036:                output.writeByte(TC_REFERENCE);
1037:                output.writeInt(handle.intValue());
1038:            }
1039:
1040:            /**
1041:             * Write primitive data of type double (<code>value</code>)into the
1042:             * receiver's underlying stream.
1043:             * 
1044:             * @param value
1045:             *            The primitive data to write
1046:             * 
1047:             * @throws IOException
1048:             *             If an IO exception happened when writing the primitive data.
1049:             */
1050:            public void writeDouble(double value) throws IOException {
1051:                checkWritePrimitiveTypes();
1052:                primitiveTypes.writeDouble(value);
1053:            }
1054:
1055:            /**
1056:             * Writes a collection of field descriptors (name, type name, etc) for the
1057:             * class descriptor <code>classDesc</code> (an
1058:             * <code>ObjectStreamClass</code>)
1059:             * 
1060:             * @param classDesc
1061:             *            The class descriptor (an <code>ObjectStreamClass</code>)
1062:             *            for which to write field information
1063:             * @param externalizable
1064:             *            true if the descriptors are externalizable
1065:             * 
1066:             * @throws IOException
1067:             *             If an IO exception happened when writing the field
1068:             *             descriptors.
1069:             * 
1070:             * @see #writeObject(Object)
1071:             */
1072:            private void writeFieldDescriptors(ObjectStreamClass classDesc,
1073:                    boolean externalizable) throws IOException {
1074:                Class<?> loadedClass = classDesc.forClass();
1075:                ObjectStreamField[] fields = null;
1076:                int fieldCount = 0;
1077:
1078:                // The fields of String are not needed since Strings are treated as
1079:                // primitive types
1080:                if (!externalizable
1081:                        && loadedClass != ObjectStreamClass.STRINGCLASS) {
1082:                    fields = classDesc.fields();
1083:                    fieldCount = fields.length;
1084:                }
1085:
1086:                // Field count
1087:                output.writeShort(fieldCount);
1088:                // Field names
1089:                for (int i = 0; i < fieldCount; i++) {
1090:                    ObjectStreamField f = fields[i];
1091:                    output.writeByte(f.getTypeCode());
1092:                    output.writeUTF(f.getName());
1093:                    if (!f.isPrimitive()) {
1094:                        writeObject(f.getTypeString());
1095:                    }
1096:                }
1097:            }
1098:
1099:            /**
1100:             * Write the fields of the object being dumped. The stream will use the
1101:             * currently active <code>PutField</code> object, allowing users to dump
1102:             * emulated fields, for cross-loading compatibility when a class definition
1103:             * changes.
1104:             * 
1105:             * @throws IOException
1106:             *             If an IO error occurs
1107:             * 
1108:             * @see #putFields
1109:             */
1110:            public void writeFields() throws IOException {
1111:                // Has to have fields to write
1112:                if (currentPutField == null) {
1113:                    throw new NotActiveException();
1114:                }
1115:                writeFieldValues(currentPutField);
1116:            }
1117:
1118:            /**
1119:             * Writes a collection of field values for the emulated fields
1120:             * <code>emulatedFields</code>
1121:             * 
1122:             * @param emulatedFields
1123:             *            an <code>EmulatedFieldsForDumping</code>, concrete subclass
1124:             *            of <code>PutField</code>
1125:             * 
1126:             * @throws IOException
1127:             *             If an IO exception happened when writing the field values.
1128:             * 
1129:             * @see #writeFields
1130:             * @see #writeObject(Object)
1131:             */
1132:            private void writeFieldValues(
1133:                    EmulatedFieldsForDumping emulatedFields) throws IOException {
1134:                EmulatedFields accessibleSimulatedFields = emulatedFields
1135:                        .emulatedFields(); // Access internal fields which we can
1136:                // set/get. Users can't do this.
1137:                EmulatedFields.ObjectSlot[] slots = accessibleSimulatedFields
1138:                        .slots();
1139:                for (int i = 0; i < slots.length; i++) {
1140:                    EmulatedFields.ObjectSlot slot = slots[i];
1141:                    Object fieldValue = slot.getFieldValue();
1142:                    Class<?> type = slot.getField().getType();
1143:                    // WARNING - default values exist for each primitive type
1144:                    if (type == Integer.TYPE) {
1145:                        output
1146:                                .writeInt(fieldValue != null ? ((Integer) fieldValue)
1147:                                        .intValue()
1148:                                        : 0);
1149:                    } else if (type == Byte.TYPE) {
1150:                        output
1151:                                .writeByte(fieldValue != null ? ((Byte) fieldValue)
1152:                                        .byteValue()
1153:                                        : (byte) 0);
1154:                    } else if (type == Character.TYPE) {
1155:                        output
1156:                                .writeChar(fieldValue != null ? ((Character) fieldValue)
1157:                                        .charValue()
1158:                                        : (char) 0);
1159:                    } else if (type == Short.TYPE) {
1160:                        output
1161:                                .writeShort(fieldValue != null ? ((Short) fieldValue)
1162:                                        .shortValue()
1163:                                        : (short) 0);
1164:                    } else if (type == Boolean.TYPE) {
1165:                        output
1166:                                .writeBoolean(fieldValue != null ? ((Boolean) fieldValue)
1167:                                        .booleanValue()
1168:                                        : false);
1169:                    } else if (type == Long.TYPE) {
1170:                        output
1171:                                .writeLong(fieldValue != null ? ((Long) fieldValue)
1172:                                        .longValue()
1173:                                        : (long) 0);
1174:                    } else if (type == Float.TYPE) {
1175:                        output
1176:                                .writeFloat(fieldValue != null ? ((Float) fieldValue)
1177:                                        .floatValue()
1178:                                        : (float) 0);
1179:                    } else if (type == Double.TYPE) {
1180:                        output
1181:                                .writeDouble(fieldValue != null ? ((Double) fieldValue)
1182:                                        .doubleValue()
1183:                                        : (double) 0);
1184:                    } else {
1185:                        // Either array or Object
1186:                        writeObject(fieldValue);
1187:                    }
1188:                }
1189:            }
1190:
1191:            /**
1192:             * Writes a collection of field values for the fields described by class
1193:             * descriptor <code>classDesc</code> (an <code>ObjectStreamClass</code>).
1194:             * This is the default mechanism, when emulated fields (an
1195:             * <code>PutField</code>) are not used. Actual values to dump are fetched
1196:             * directly from object <code>obj</code>.
1197:             * 
1198:             * @param obj
1199:             *            Instance from which to fetch field values to dump.
1200:             * @param classDesc
1201:             *            A class descriptor (an <code>ObjectStreamClass</code>)
1202:             *            defining which fields should be dumped.
1203:             * 
1204:             * @throws IOException
1205:             *             If an IO exception happened when writing the field values.
1206:             * 
1207:             * @see #writeObject(Object)
1208:             */
1209:            private void writeFieldValues(Object obj,
1210:                    ObjectStreamClass classDesc) throws IOException {
1211:                ObjectStreamField[] fields = classDesc.fields();
1212:                Class<?> declaringClass = classDesc.forClass();
1213:                for (int i = 0; i < fields.length; i++) {
1214:                    try {
1215:                        // Code duplication starts, just because Java is typed
1216:                        ObjectStreamField fieldDesc = fields[i];
1217:                        if (fieldDesc.isPrimitive()) {
1218:                            switch (fieldDesc.getTypeCode()) {
1219:                            case 'B':
1220:                                output.writeByte(getFieldByte(obj,
1221:                                        declaringClass, fieldDesc.getName()));
1222:                                break;
1223:                            case 'C':
1224:                                output.writeChar(getFieldChar(obj,
1225:                                        declaringClass, fieldDesc.getName()));
1226:                                break;
1227:                            case 'D':
1228:                                output.writeDouble(getFieldDouble(obj,
1229:                                        declaringClass, fieldDesc.getName()));
1230:                                break;
1231:                            case 'F':
1232:                                output.writeFloat(getFieldFloat(obj,
1233:                                        declaringClass, fieldDesc.getName()));
1234:                                break;
1235:                            case 'I':
1236:                                output.writeInt(getFieldInt(obj,
1237:                                        declaringClass, fieldDesc.getName()));
1238:                                break;
1239:                            case 'J':
1240:                                output.writeLong(getFieldLong(obj,
1241:                                        declaringClass, fieldDesc.getName()));
1242:                                break;
1243:                            case 'S':
1244:                                output.writeShort(getFieldShort(obj,
1245:                                        declaringClass, fieldDesc.getName()));
1246:                                break;
1247:                            case 'Z':
1248:                                output.writeBoolean(getFieldBool(obj,
1249:                                        declaringClass, fieldDesc.getName()));
1250:                                break;
1251:                            default:
1252:                                throw new IOException(
1253:                                        org.apache.harmony.luni.util.Msg
1254:                                                .getString(
1255:                                                        "K00d5", fieldDesc.getTypeCode())); //$NON-NLS-1$
1256:                            }
1257:                        } else {
1258:                            // Object type (array included).
1259:                            Object field = getFieldObj(obj, declaringClass,
1260:                                    fieldDesc.getName(), fieldDesc
1261:                                            .getTypeString());
1262:                            if (fieldDesc.isUnshared()) {
1263:                                writeUnshared(field);
1264:                            } else {
1265:                                writeObject(field);
1266:                            }
1267:                        }
1268:                    } catch (NoSuchFieldError nsf) {
1269:                        // The user defined serialPersistentFields but did not provide
1270:                        // the glue to transfer values,
1271:                        // (in writeObject) so we end up using the default mechanism and
1272:                        // fail to set the emulated field
1273:                        throw new InvalidClassException(classDesc.getName());
1274:                    }
1275:                }
1276:            }
1277:
1278:            /**
1279:             * Write primitive data of type float (<code>value</code>)into the
1280:             * receiver's underlying stream.
1281:             * 
1282:             * @param value
1283:             *            The primitive data to write
1284:             * 
1285:             * @throws IOException
1286:             *             If an IO exception happened when writing the primitive data.
1287:             */
1288:            public void writeFloat(float value) throws IOException {
1289:                checkWritePrimitiveTypes();
1290:                primitiveTypes.writeFloat(value);
1291:            }
1292:
1293:            /**
1294:             * Walks the hierarchy of classes described by class descriptor
1295:             * <code>classDesc</code> and writes the field values corresponding to
1296:             * fields declared by the corresponding class descriptor. The instance to
1297:             * fetch field values from is <code>object</code>. If the class
1298:             * (corresponding to class descriptor <code>classDesc</code>) defines
1299:             * private instance method <code>writeObject</code> it will be used to
1300:             * dump field values.
1301:             * 
1302:             * @param object
1303:             *            Instance from which to fetch field values to dump.
1304:             * @param classDesc
1305:             *            A class descriptor (an <code>ObjectStreamClass</code>)
1306:             *            defining which fields should be dumped.
1307:             * 
1308:             * @throws IOException
1309:             *             If an IO exception happened when writing the field values in
1310:             *             the hierarchy.
1311:             * @throws NotActiveException
1312:             *             If the given object is not active
1313:             * 
1314:             * @see #defaultWriteObject
1315:             * @see #writeObject(Object)
1316:             */
1317:            private void writeHierarchy(Object object,
1318:                    ObjectStreamClass classDesc) throws IOException,
1319:                    NotActiveException {
1320:                // We can't be called from just anywhere. There are rules.
1321:                if (object == null) {
1322:                    throw new NotActiveException();
1323:                }
1324:
1325:                // Fields are written from class closest to Object to leaf class
1326:                // (down the chain)
1327:                if (classDesc.getSuperclass() != null) {
1328:                    // first
1329:                    writeHierarchy(object, classDesc.getSuperclass());
1330:                }
1331:
1332:                // Have to do this before calling defaultWriteObject or anything
1333:                // that calls defaultWriteObject
1334:                currentObject = object;
1335:                currentClass = classDesc;
1336:
1337:                // See if the object has a writeObject method. If so, run it
1338:                boolean executed = false;
1339:                try {
1340:                    if (classDesc.hasMethodWriteObject()) {
1341:                        final Method method = classDesc.getMethodWriteObject();
1342:                        try {
1343:                            method.invoke(object, new Object[] { this  });
1344:                            executed = true;
1345:                        } catch (InvocationTargetException e) {
1346:                            Throwable ex = e.getTargetException();
1347:                            if (ex instanceof  RuntimeException) {
1348:                                throw (RuntimeException) ex;
1349:                            } else if (ex instanceof  Error) {
1350:                                throw (Error) ex;
1351:                            }
1352:                            throw (IOException) ex;
1353:                        } catch (IllegalAccessException e) {
1354:                            throw new RuntimeException(e.toString());
1355:                        }
1356:                    }
1357:
1358:                    if (executed) {
1359:                        drain();
1360:                        output.writeByte(TC_ENDBLOCKDATA);
1361:                    } else {
1362:                        // If the object did not have a writeMethod, call
1363:                        // defaultWriteObject
1364:                        defaultWriteObject();
1365:                    }
1366:                } finally {
1367:                    // Cleanup, needs to run always so that we can later detect
1368:                    // invalid calls to defaultWriteObject
1369:                    currentObject = null;
1370:                    currentClass = null;
1371:                    currentPutField = null;
1372:                }
1373:            }
1374:
1375:            /**
1376:             * Write primitive data of type int (<code>value</code>)into the
1377:             * receiver's underlying stream.
1378:             * 
1379:             * @param value
1380:             *            The primitive data to write
1381:             * 
1382:             * @throws IOException
1383:             *             If an IO exception happened when writing the primitive data.
1384:             */
1385:            public void writeInt(int value) throws IOException {
1386:                checkWritePrimitiveTypes();
1387:                primitiveTypes.writeInt(value);
1388:            }
1389:
1390:            /**
1391:             * Write primitive data of type long (<code>value</code>)into the
1392:             * receiver's underlying stream.
1393:             * 
1394:             * @param value
1395:             *            The primitive data to write
1396:             * 
1397:             * @throws IOException
1398:             *             If an IO exception happened when writing the primitive data.
1399:             */
1400:            public void writeLong(long value) throws IOException {
1401:                checkWritePrimitiveTypes();
1402:                primitiveTypes.writeLong(value);
1403:            }
1404:
1405:            /**
1406:             * Write array <code>array</code> of class <code>arrayClass</code> with
1407:             * component type <code>componentType</code> into the receiver. It is
1408:             * assumed the array has not been dumped yet. Return an <code>Integer</code>
1409:             * that represents the handle for this object (array) which is dumped here.
1410:             * 
1411:             * @param array
1412:             *            The array object to dump
1413:             * @param arrayClass
1414:             *            A <code>java.lang.Class</code> representing the class of the
1415:             *            array
1416:             * @param componentType
1417:             *            A <code>java.lang.Class</code> representing the array
1418:             *            component type
1419:             * @return the handle assigned to the array
1420:             * 
1421:             * @throws IOException
1422:             *             If an IO exception happened when writing the array.
1423:             */
1424:            private Integer writeNewArray(Object array, Class<?> arrayClass,
1425:                    Class<?> componentType, boolean unshared)
1426:                    throws IOException {
1427:                output.writeByte(TC_ARRAY);
1428:                writeClassDescForClass(arrayClass);
1429:
1430:                Integer previousHandle = objectsWritten.get(array);
1431:                Integer handle = registerObjectWritten(array);
1432:                if (unshared) {
1433:                    // remove reference to unshared object
1434:                    removeUnsharedReference(array, previousHandle);
1435:                }
1436:
1437:                // Now we have code duplication just because Java is typed. We have to
1438:                // write N elements and assign to array positions, but we must typecast
1439:                // the array first, and also call different methods depending on the
1440:                // elements.
1441:
1442:                if (componentType.isPrimitive()) {
1443:                    if (componentType == Integer.TYPE) {
1444:                        int[] intArray = (int[]) array;
1445:                        output.writeInt(intArray.length);
1446:                        for (int i = 0; i < intArray.length; i++) {
1447:                            output.writeInt(intArray[i]);
1448:                        }
1449:                    } else if (componentType == Byte.TYPE) {
1450:                        byte[] byteArray = (byte[]) array;
1451:                        output.writeInt(byteArray.length);
1452:                        output.write(byteArray, 0, byteArray.length);
1453:                    } else if (componentType == Character.TYPE) {
1454:                        char[] charArray = (char[]) array;
1455:                        output.writeInt(charArray.length);
1456:                        for (int i = 0; i < charArray.length; i++) {
1457:                            output.writeChar(charArray[i]);
1458:                        }
1459:                    } else if (componentType == Short.TYPE) {
1460:                        short[] shortArray = (short[]) array;
1461:                        output.writeInt(shortArray.length);
1462:                        for (int i = 0; i < shortArray.length; i++) {
1463:                            output.writeShort(shortArray[i]);
1464:                        }
1465:                    } else if (componentType == Boolean.TYPE) {
1466:                        boolean[] booleanArray = (boolean[]) array;
1467:                        output.writeInt(booleanArray.length);
1468:                        for (int i = 0; i < booleanArray.length; i++) {
1469:                            output.writeBoolean(booleanArray[i]);
1470:                        }
1471:                    } else if (componentType == Long.TYPE) {
1472:                        long[] longArray = (long[]) array;
1473:                        output.writeInt(longArray.length);
1474:                        for (int i = 0; i < longArray.length; i++) {
1475:                            output.writeLong(longArray[i]);
1476:                        }
1477:                    } else if (componentType == Float.TYPE) {
1478:                        float[] floatArray = (float[]) array;
1479:                        output.writeInt(floatArray.length);
1480:                        for (int i = 0; i < floatArray.length; i++) {
1481:                            output.writeFloat(floatArray[i]);
1482:                        }
1483:                    } else if (componentType == Double.TYPE) {
1484:                        double[] doubleArray = (double[]) array;
1485:                        output.writeInt(doubleArray.length);
1486:                        for (int i = 0; i < doubleArray.length; i++) {
1487:                            output.writeDouble(doubleArray[i]);
1488:                        }
1489:                    } else {
1490:                        throw new InvalidClassException(
1491:                                org.apache.harmony.luni.util.Msg.getString(
1492:                                        "K00d7", arrayClass.getName())); //$NON-NLS-1$
1493:                    }
1494:                } else {
1495:                    // Array of Objects
1496:                    Object[] objectArray = (Object[]) array;
1497:                    output.writeInt(objectArray.length);
1498:                    for (int i = 0; i < objectArray.length; i++) {
1499:                        writeObject(objectArray[i]);
1500:                    }
1501:                }
1502:                return handle;
1503:            }
1504:
1505:            /**
1506:             * Write class <code>object</code> into the receiver. It is assumed the
1507:             * class has not been dumped yet. Classes are not really dumped, but a class
1508:             * descriptor (<code>ObjectStreamClass</code>) that corresponds to them.
1509:             * Return an <code>Integer</code> that represents the handle for this
1510:             * object (class) which is dumped here.
1511:             * 
1512:             * @param object
1513:             *            The <code>java.lang.Class</code> object to dump
1514:             * @return the handle assigned to the class being dumped
1515:             * 
1516:             * @throws IOException
1517:             *             If an IO exception happened when writing the class.
1518:             */
1519:            private Integer writeNewClass(Class<?> object, boolean unshared)
1520:                    throws IOException {
1521:                output.writeByte(TC_CLASS);
1522:
1523:                // Instances of java.lang.Class are always Serializable, even if their
1524:                // instances aren't (e.g. java.lang.Object.class).
1525:                // We cannot call lookup because it returns null if the parameter
1526:                // represents instances that cannot be serialized, and that is not what
1527:                // we want.
1528:
1529:                // The handle for the classDesc is NOT the handle for the class object
1530:                // being dumped. We must allocate a new handle and return it.
1531:                if (object.isEnum()) {
1532:                    writeEnumDesc(object, unshared);
1533:                } else {
1534:                    writeClassDesc(ObjectStreamClass.lookupStreamClass(object),
1535:                            unshared);
1536:                }
1537:
1538:                Integer previousHandle = objectsWritten.get(object);
1539:                Integer handle = registerObjectWritten(object);
1540:                if (unshared) {
1541:                    // remove reference to unshared object
1542:                    removeUnsharedReference(object, previousHandle);
1543:                }
1544:
1545:                return handle;
1546:            }
1547:
1548:            /**
1549:             * Write class descriptor <code>classDesc</code> into the receiver. It is
1550:             * assumed the class descriptor has not been dumped yet. The class
1551:             * descriptors for the superclass chain will be dumped as well. Return an
1552:             * <code>Integer</code> that represents the handle for this object (class
1553:             * descriptor) which is dumped here.
1554:             * 
1555:             * @param classDesc
1556:             *            The <code>ObjectStreamClass</code> object to dump
1557:             * 
1558:             * @throws IOException
1559:             *             If an IO exception happened when writing the class
1560:             *             descriptor.
1561:             */
1562:            private void writeNewClassDesc(ObjectStreamClass classDesc)
1563:                    throws IOException {
1564:                output.writeUTF(classDesc.getName());
1565:                output.writeLong(classDesc.getSerialVersionUID());
1566:                byte flags = classDesc.getFlags();
1567:                boolean externalizable = false;
1568:                externalizable = ObjectStreamClass.isExternalizable(classDesc
1569:                        .forClass());
1570:
1571:                if (externalizable) {
1572:                    if (protocolVersion == PROTOCOL_VERSION_1) {
1573:                        flags &= NOT_SC_BLOCK_DATA;
1574:                    } else {
1575:                        // Change for 1.2. Objects can be saved in old format
1576:                        // (PROTOCOL_VERSION_1) or in the 1.2 format (PROTOCOL_VERSION_2).
1577:                        flags |= SC_BLOCK_DATA;
1578:                    }
1579:                }
1580:                output.writeByte(flags);
1581:                if ((SC_ENUM | SC_SERIALIZABLE) != classDesc.getFlags()) {
1582:                    writeFieldDescriptors(classDesc, externalizable);
1583:                } else {
1584:                    // enum write no fields
1585:                    output.writeShort(0);
1586:                }
1587:            }
1588:
1589:            /**
1590:             * Write class descriptor <code>classDesc</code> into the receiver.
1591:             * 
1592:             * @param classDesc
1593:             *            The <code>ObjectStreamClass</code> object to dump
1594:             * 
1595:             * @throws IOException
1596:             *             If an IO exception happened when writing the class
1597:             *             descriptor.
1598:             */
1599:            protected void writeClassDescriptor(ObjectStreamClass classDesc)
1600:                    throws IOException {
1601:                writeNewClassDesc(classDesc);
1602:            }
1603:
1604:            /**
1605:             * Write exception <code>ex</code> into the receiver. It is assumed the
1606:             * exception has not been dumped yet. Return an <code>Integer</code> that
1607:             * represents the handle for this object (exception) which is dumped here.
1608:             * This is used to dump the exception instance that happened (if any) when
1609:             * dumping the original object graph. The set of seen objects will be reset
1610:             * just before and just after dumping this exception object.
1611:             * 
1612:             * When exceptions are found normally in the object graph, they are dumped
1613:             * as a regular object, and not by this method. In that case, the set of
1614:             * "known objects" is not reset.
1615:             * 
1616:             * @param ex
1617:             *            Exception object to dump
1618:             * 
1619:             * @throws IOException
1620:             *             If an IO exception happened when writing the exception
1621:             *             object.
1622:             */
1623:            private void writeNewException(Exception ex) throws IOException {
1624:                output.writeByte(TC_EXCEPTION);
1625:                resetSeenObjects();
1626:                writeObjectInternal(ex, false, false, false); // No replacements
1627:                resetSeenObjects();
1628:            }
1629:
1630:            /**
1631:             * Write object <code>object</code> of class <code>theClass</code> into
1632:             * the receiver. It is assumed the object has not been dumped yet. Return an
1633:             * <code>Integer</code> that represents the handle for this object which
1634:             * is dumped here.
1635:             * 
1636:             * If the object implements <code>Externalizable</code> its
1637:             * <code>writeExternal</code> is called. Otherwise, all fields described
1638:             * by the class hierarchy is dumped. Each class can define how its declared
1639:             * instance fields are dumped by defining a private method
1640:             * <code>writeObject</code>
1641:             * 
1642:             * @param object
1643:             *            The object to dump
1644:             * @param theClass
1645:             *            A <code>java.lang.Class</code> representing the class of the
1646:             *            object
1647:             * @param unshared
1648:             *            Write the object unshared
1649:             * @return the handle assigned to the object
1650:             * 
1651:             * @throws IOException
1652:             *             If an IO exception happened when writing the object.
1653:             */
1654:            private Integer writeNewObject(Object object, Class<?> theClass,
1655:                    boolean unshared) throws IOException {
1656:                // Not String, not null, not array, not cyclic reference
1657:
1658:                EmulatedFieldsForDumping originalCurrentPutField = currentPutField; // save
1659:                currentPutField = null; // null it, to make sure one will be computed if
1660:                // needed
1661:
1662:                boolean externalizable = ObjectStreamClass
1663:                        .isExternalizable(theClass);
1664:                boolean serializable = ObjectStreamClass
1665:                        .isSerializable(theClass);
1666:                if (!externalizable && !serializable) {
1667:                    // Object is neither externalizable nor serializable. Error
1668:                    throw new NotSerializableException(theClass.getName());
1669:                }
1670:
1671:                // Either serializable or externalizable, now we can save info
1672:                output.writeByte(TC_OBJECT);
1673:                writeClassDescForClass(theClass);
1674:                Integer previousHandle = objectsWritten.get(object);
1675:                Integer handle = registerObjectWritten(object);
1676:
1677:                // This is how we know what to do in defaultWriteObject. And it is also
1678:                // used by defaultWriteObject to check if it was called from an invalid
1679:                // place.
1680:                // It allows writeExternal to call defaultWriteObject and have it work.
1681:                currentObject = object;
1682:                currentClass = ObjectStreamClass.lookup(theClass);
1683:                try {
1684:                    if (externalizable) {
1685:                        boolean noBlockData = protocolVersion == PROTOCOL_VERSION_1;
1686:                        if (noBlockData) {
1687:                            primitiveTypes = output;
1688:                        }
1689:                        // Object is externalizable, just call its own method
1690:                        ((Externalizable) object).writeExternal(this );
1691:                        if (noBlockData) {
1692:                            primitiveTypes = null;
1693:                        } else {
1694:                            // Similar to the code in writeHierarchy when object
1695:                            // implements writeObject.
1696:                            // Any primitive data has to be flushed and a tag must be
1697:                            // written
1698:                            drain();
1699:                            output.writeByte(TC_ENDBLOCKDATA);
1700:                        }
1701:                    } else { // If it got here, it has to be Serializable
1702:                        // Object is serializable. Walk the class chain writing the
1703:                        // fields
1704:                        writeHierarchy(object, currentClass);
1705:                    }
1706:                } finally {
1707:                    // Cleanup, needs to run always so that we can later detect invalid
1708:                    // calls to defaultWriteObject
1709:                    if (unshared) {
1710:                        // remove reference to unshared object
1711:                        removeUnsharedReference(object, previousHandle);
1712:                    }
1713:                    currentObject = null;
1714:                    currentClass = null;
1715:                    currentPutField = originalCurrentPutField;
1716:                }
1717:
1718:                return handle;
1719:            }
1720:
1721:            /**
1722:             * Write String <code>object</code> into the receiver. It is assumed the
1723:             * String has not been dumped yet. Return an <code>Integer</code> that
1724:             * represents the handle for this object (String) which is dumped here.
1725:             * Strings are saved in UTF format.
1726:             * 
1727:             * @param object
1728:             *            The <code>java.lang.String</code> object to dump
1729:             * @return the handle assigned to the String being dumped
1730:             * 
1731:             * @throws IOException
1732:             *             If an IO exception happened when writing the String.
1733:             */
1734:            private Integer writeNewString(String object, boolean unshared)
1735:                    throws IOException {
1736:                long count = output.countUTFBytes(object);
1737:                if (count <= 0xffff) {
1738:                    output.writeByte(TC_STRING);
1739:                    output.writeShort((short) count);
1740:                } else {
1741:                    output.writeByte(TC_LONGSTRING);
1742:                    output.writeLong(count);
1743:                }
1744:                output.writeUTFBytes(object, count);
1745:
1746:                Integer previousHandle = objectsWritten.get(object);
1747:                Integer handle = registerObjectWritten(object);
1748:                if (unshared) {
1749:                    // remove reference to unshared object
1750:                    removeUnsharedReference(object, previousHandle);
1751:                }
1752:                return handle;
1753:            }
1754:
1755:            /**
1756:             * Write a special tag that indicates the value <code>null</code> into the
1757:             * receiver.
1758:             * 
1759:             * @throws IOException
1760:             *             If an IO exception happened when writing the tag for
1761:             *             <code>null</code>.
1762:             */
1763:            private void writeNull() throws IOException {
1764:                output.writeByte(TC_NULL);
1765:            }
1766:
1767:            /**
1768:             * Write object <code>object</code> into the receiver's underlying stream.
1769:             * 
1770:             * @param object
1771:             *            The object to write
1772:             * 
1773:             * @throws IOException
1774:             *             If an IO exception happened when writing the object
1775:             * 
1776:             * @see ObjectInputStream#readObject()
1777:             */
1778:            public final void writeObject(Object object) throws IOException {
1779:                writeObject(object, false);
1780:            }
1781:
1782:            /**
1783:             * Write object <code>object</code> into the receiver's underlying stream
1784:             * unshared with previously written identical objects.
1785:             * 
1786:             * @param object
1787:             *            The object to write
1788:             * 
1789:             * @throws IOException
1790:             *             If an IO exception happened when writing the object
1791:             * 
1792:             * @see ObjectInputStream#readObject()
1793:             */
1794:            public void writeUnshared(Object object) throws IOException {
1795:                writeObject(object, true);
1796:            }
1797:
1798:            private void writeObject(Object object, boolean unshared)
1799:                    throws IOException {
1800:                boolean setOutput = (primitiveTypes == output);
1801:                if (setOutput) {
1802:                    primitiveTypes = null;
1803:                }
1804:                // This is the spec'ed behavior in JDK 1.2. Very bizarre way to allow
1805:                // behavior overriding.
1806:                if (subclassOverridingImplementation && !unshared) {
1807:                    writeObjectOverride(object);
1808:                } else {
1809:
1810:                    try {
1811:                        // First we need to flush primitive types if they were written
1812:                        drain();
1813:                        // Actual work, and class-based replacement should be computed
1814:                        // if needed.
1815:                        writeObjectInternal(object, unshared, true, true);
1816:                        if (setOutput) {
1817:                            primitiveTypes = output;
1818:                        }
1819:                    } catch (IOException ioEx1) {
1820:                        // This will make it pass through until the top caller. It also
1821:                        // lets it pass through the nested exception.
1822:                        if (nestedLevels == 0 && ioEx1 != nestedException) {
1823:                            try {
1824:                                writeNewException(ioEx1);
1825:                            } catch (IOException ioEx2) {
1826:                                nestedException.fillInStackTrace();
1827:                                throw nestedException;
1828:                            }
1829:                        }
1830:                        throw ioEx1; // and then we propagate the original exception
1831:                    }
1832:                }
1833:            }
1834:
1835:            /**
1836:             * Write object <code>object</code> into the receiver's underlying stream.
1837:             * 
1838:             * @param object
1839:             *            The object to write
1840:             * @param unshared
1841:             *            Write the object unshared
1842:             * @param computeClassBasedReplacement
1843:             *            A boolean indicating if class-based replacement should be
1844:             *            computed (if supported) for the object.
1845:             * @param computeStreamReplacement
1846:             *            A boolean indicating if stream-based replacement should be
1847:             *            computed (if supported) for the object.
1848:             * @return the handle assigned to the final object being dumped
1849:             * 
1850:             * @throws IOException
1851:             *             If an IO exception happened when writing the object
1852:             * 
1853:             * @see ObjectInputStream#readObject()
1854:             */
1855:            private Integer writeObjectInternal(Object object,
1856:                    boolean unshared, boolean computeClassBasedReplacement,
1857:                    boolean computeStreamReplacement) throws IOException {
1858:
1859:                if (object == null) {
1860:                    writeNull();
1861:                    return null;
1862:                }
1863:                Integer handle = null;
1864:                if (!unshared) {
1865:                    handle = dumpCycle(object);
1866:                    if (handle != null) {
1867:                        return handle; // cyclic reference
1868:                    }
1869:                }
1870:
1871:                // Non-null object, first time seen...
1872:                Class<?> objClass = object.getClass();
1873:                nestedLevels++;
1874:                try {
1875:
1876:                    if (!(enableReplace && computeStreamReplacement)) {
1877:                        // Is it a Class ?
1878:                        if (objClass == ObjectStreamClass.CLASSCLASS) {
1879:                            return writeNewClass((Class<?>) object, unshared);
1880:                        }
1881:                        // Is it an ObjectStreamClass ?
1882:                        if (objClass == ObjectStreamClass.OBJECTSTREAMCLASSCLASS) {
1883:                            return writeClassDesc((ObjectStreamClass) object,
1884:                                    unshared);
1885:                        }
1886:                    }
1887:
1888:                    if (ObjectStreamClass.isSerializable(object.getClass())
1889:                            && computeClassBasedReplacement) {
1890:                        ObjectStreamClass clDesc = ObjectStreamClass
1891:                                .lookupStreamClass(objClass);
1892:                        if (clDesc.hasMethodWriteReplace()) {
1893:                            Method methodWriteReplace = clDesc
1894:                                    .getMethodWriteReplace();
1895:                            Object replObj = null;
1896:                            try {
1897:                                replObj = methodWriteReplace.invoke(object,
1898:                                        (Object[]) null);
1899:                            } catch (IllegalAccessException iae) {
1900:                                replObj = object;
1901:                            } catch (InvocationTargetException ite) {
1902:                                // WARNING - Not sure this is the right thing to do
1903:                                // if we can't run the method
1904:                                Throwable target = ite.getTargetException();
1905:                                if (target instanceof  ObjectStreamException) {
1906:                                    throw (ObjectStreamException) target;
1907:                                } else if (target instanceof  Error) {
1908:                                    throw (Error) target;
1909:                                } else {
1910:                                    throw (RuntimeException) target;
1911:                                }
1912:                            }
1913:                            if (replObj != object) {
1914:                                // All over, class-based replacement off this time.
1915:                                Integer replacementHandle = writeObjectInternal(
1916:                                        replObj, false, false,
1917:                                        computeStreamReplacement);
1918:                                // Make the original object also map to the same
1919:                                // handle.
1920:                                if (replacementHandle != null) {
1921:                                    registerObjectWritten(object,
1922:                                            replacementHandle);
1923:                                }
1924:                                return replacementHandle;
1925:                            }
1926:                        }
1927:
1928:                    }
1929:
1930:                    // We get here either if class-based replacement was not needed or
1931:                    // if it was needed but produced the same object or if it could not
1932:                    // be computed.
1933:                    if (enableReplace && computeStreamReplacement) {
1934:                        // Now we compute the stream-defined replacement.
1935:                        Object streamReplacement = replaceObject(object);
1936:                        if (streamReplacement != object) {
1937:                            // All over, class-based replacement off this time.
1938:                            Integer replacementHandle = writeObjectInternal(
1939:                                    streamReplacement, false,
1940:                                    computeClassBasedReplacement, false);
1941:                            // Make the original object also map to the same handle.
1942:                            if (replacementHandle != null) {
1943:                                registerObjectWritten(object, replacementHandle);
1944:                            }
1945:                            return replacementHandle;
1946:                        }
1947:                    }
1948:
1949:                    // We get here if stream-based replacement produced the same object
1950:
1951:                    // Is it a Class ?
1952:                    if (objClass == ObjectStreamClass.CLASSCLASS) {
1953:                        return writeNewClass((Class<?>) object, unshared);
1954:                    }
1955:
1956:                    // Is it an ObjectStreamClass ?
1957:                    if (objClass == ObjectStreamClass.OBJECTSTREAMCLASSCLASS) {
1958:                        return writeClassDesc((ObjectStreamClass) object,
1959:                                unshared);
1960:                    }
1961:
1962:                    // Is it a String ? (instanceof, but == is faster)
1963:                    if (objClass == ObjectStreamClass.STRINGCLASS) {
1964:                        return writeNewString((String) object, unshared);
1965:                    }
1966:
1967:                    // Is it an Array ?
1968:                    if (objClass.isArray()) {
1969:                        return writeNewArray(object, objClass, objClass
1970:                                .getComponentType(), unshared);
1971:                    }
1972:
1973:                    if (object instanceof  Enum) {
1974:                        return writeNewEnum(object, objClass, unshared);
1975:                    }
1976:
1977:                    // Not a String or Class or Array. Default procedure.
1978:                    return writeNewObject(object, objClass, unshared);
1979:                } finally {
1980:                    nestedLevels--;
1981:                }
1982:            }
1983:
1984:            // write for Enum Class Desc only, which is different from other classes
1985:            private ObjectStreamClass writeEnumDesc(Class<?> theClass,
1986:                    boolean unshared) throws IOException {
1987:                // write classDesc, classDesc for enum is different
1988:                ObjectStreamClass classDesc = ObjectStreamClass
1989:                        .lookup(theClass);
1990:                // set flag for enum, the flag is (SC_SERIALIZABLE | SC_ENUM)
1991:                classDesc.setFlags((byte) (SC_SERIALIZABLE | SC_ENUM));
1992:                Integer previousHandle = objectsWritten.get(classDesc);
1993:                Integer handle = null;
1994:                if (!unshared) {
1995:                    handle = dumpCycle(classDesc);
1996:                }
1997:                if (handle == null) {
1998:                    Class<?> classToWrite = classDesc.forClass();
1999:                    // If we got here, it is a new (non-null) classDesc that will have
2000:                    // to be registered as well
2001:                    registerObjectWritten(classDesc);
2002:
2003:                    output.writeByte(TC_CLASSDESC);
2004:                    if (protocolVersion == PROTOCOL_VERSION_1) {
2005:                        writeNewClassDesc(classDesc);
2006:                    } else {
2007:                        // So write...() methods can be used by
2008:                        // subclasses during writeClassDescriptor()
2009:                        primitiveTypes = output;
2010:                        writeClassDescriptor(classDesc);
2011:                        primitiveTypes = null;
2012:                    }
2013:                    // Extra class info (optional)
2014:                    annotateClass(classToWrite);
2015:                    drain(); // flush primitive types in the annotation
2016:                    output.writeByte(TC_ENDBLOCKDATA);
2017:                    // write super class
2018:                    ObjectStreamClass super Class = classDesc.getSuperclass();
2019:                    if (null != super Class) {
2020:                        // super class is also enum
2021:                        super Class.setFlags((byte) (SC_SERIALIZABLE | SC_ENUM));
2022:                        writeEnumDesc(super Class.forClass(), unshared);
2023:                    } else {
2024:                        output.writeByte(TC_NULL);
2025:                    }
2026:                    if (unshared) {
2027:                        // remove reference to unshared object
2028:                        removeUnsharedReference(classDesc, previousHandle);
2029:                    }
2030:                }
2031:                return classDesc;
2032:            }
2033:
2034:            private Integer writeNewEnum(Object object, Class<?> theClass,
2035:                    boolean unshared) throws IOException {
2036:                // write new Enum
2037:                EmulatedFieldsForDumping originalCurrentPutField = currentPutField; // save
2038:                // null it, to make sure one will be computed if needed
2039:                currentPutField = null;
2040:
2041:                output.writeByte(TC_ENUM);
2042:                while (theClass != null && !theClass.isEnum()) {
2043:                    // write enum only
2044:                    theClass = theClass.getSuperclass();
2045:                }
2046:                ObjectStreamClass classDesc = writeEnumDesc(theClass, unshared);
2047:
2048:                Integer previousHandle = objectsWritten.get(object);
2049:                Integer handle = registerObjectWritten(object);
2050:
2051:                ObjectStreamField[] fields = classDesc.getSuperclass().fields();
2052:                Class<?> declaringClass = classDesc.getSuperclass().forClass();
2053:                // Only write field "name" for enum class, which is the second field of
2054:                // enum, that is fields[1]. Ignore all non-fields and fields.length < 2
2055:                if (null != fields && fields.length > 1) {
2056:                    String str = (String) getFieldObj(object, declaringClass,
2057:                            fields[1].getName(), fields[1].getTypeString());
2058:                    Integer strhandle = null;
2059:                    if (!unshared) {
2060:                        strhandle = dumpCycle(str);
2061:                    }
2062:                    if (null == strhandle) {
2063:                        writeNewString(str, unshared);
2064:                    }
2065:                }
2066:
2067:                if (unshared) {
2068:                    // remove reference to unshared object
2069:                    removeUnsharedReference(object, previousHandle);
2070:                }
2071:                currentPutField = originalCurrentPutField;
2072:                return handle;
2073:            }
2074:
2075:            /**
2076:             * Method to be overridden by subclasses to write <code>object</code> into
2077:             * the receiver's underlying stream.
2078:             * 
2079:             * @param object
2080:             *            the object
2081:             * 
2082:             * @throws IOException
2083:             *             If an IO exception happened when writing the object
2084:             */
2085:            protected void writeObjectOverride(Object object)
2086:                    throws IOException {
2087:                if (!subclassOverridingImplementation) {
2088:                    // Subclasses must override.
2089:                    throw new IOException();
2090:                }
2091:            }
2092:
2093:            /**
2094:             * Write primitive data of type short (<code>value</code>)into the
2095:             * receiver's underlying stream.
2096:             * 
2097:             * @param value
2098:             *            The primitive data to write
2099:             * 
2100:             * @throws IOException
2101:             *             If an IO exception happened when writing the primitive data.
2102:             */
2103:            public void writeShort(int value) throws IOException {
2104:                checkWritePrimitiveTypes();
2105:                primitiveTypes.writeShort(value);
2106:            }
2107:
2108:            /**
2109:             * Writes the ObjectOutputStream header into the underlying stream.
2110:             * 
2111:             * @throws IOException
2112:             *             If an IO exception happened when writing the stream header.
2113:             */
2114:            protected void writeStreamHeader() throws IOException {
2115:                output.writeShort(STREAM_MAGIC);
2116:                output.writeShort(STREAM_VERSION);
2117:            }
2118:
2119:            /**
2120:             * Write primitive data of type String (<code>value</code>) in UTF
2121:             * format into the receiver's underlying stream.
2122:             * 
2123:             * @param value
2124:             *            The primitive data to write
2125:             * 
2126:             * @throws IOException
2127:             *             If an IO exception happened when writing the primitive data.
2128:             */
2129:            public void writeUTF(String value) throws IOException {
2130:                checkWritePrimitiveTypes();
2131:                primitiveTypes.writeUTF(value);
2132:            }
2133:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.