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.io.EmulatedFields.ObjectSlot;
0021: import java.lang.reflect.Array;
0022: import java.lang.reflect.Constructor;
0023: import java.lang.reflect.InvocationTargetException;
0024: import java.lang.reflect.Method;
0025: import java.lang.reflect.Modifier;
0026: import java.lang.reflect.Proxy;
0027: import java.security.AccessController;
0028: import java.security.PrivilegedAction;
0029: import java.util.ArrayList;
0030: import java.util.Hashtable;
0031: import java.util.Iterator;
0032:
0033: import org.apache.harmony.kernel.vm.VM;
0034: import org.apache.harmony.luni.internal.nls.Messages;
0035: import org.apache.harmony.luni.util.Msg;
0036: import org.apache.harmony.luni.util.PriviAction;
0037:
0038: /**
0039: * An ObjectInputStream can be used to load Java objects from a stream where the
0040: * objects were saved using an ObjectOutputStream. Primitive data (ints, bytes,
0041: * chars, etc) can also be loaded if the data was saved as primitive types as
0042: * well. It is invalid to attempt to read an object as primitive data.
0043: *
0044: * @see ObjectOutputStream
0045: * @see ObjectInput
0046: * @see Serializable
0047: * @see Externalizable
0048: */
0049: public class ObjectInputStream extends InputStream implements
0050: ObjectInput, ObjectStreamConstants {
0051:
0052: private static InputStream emptyStream = new ByteArrayInputStream(
0053: new byte[0]);
0054:
0055: // To put into objectsRead when reading unsharedObject
0056: private static final Object UNSHARED_OBJ = new Object(); // $NON-LOCK-1$
0057:
0058: // If the receiver has already read & not consumed a TC code
0059: private boolean hasPushbackTC;
0060:
0061: // Push back TC code if the variable above is true
0062: private byte pushbackTC;
0063:
0064: // How many nested levels to readObject. When we reach 0 we have to validate
0065: // the graph then reset it
0066: private int nestedLevels;
0067:
0068: // All objects are assigned an ID (integer handle)
0069: private int currentHandle;
0070:
0071: // Where we read from
0072: private DataInputStream input;
0073:
0074: // Where we read primitive types from
0075: private DataInputStream primitiveTypes;
0076:
0077: // Where we keep primitive type data
0078: private InputStream primitiveData = emptyStream;
0079:
0080: // Resolve object is a mechanism for replacement
0081: private boolean enableResolve;
0082:
0083: // Table mapping Integer (handle) -> Object
0084: private Hashtable<Integer, Object> objectsRead;
0085:
0086: // Used by defaultReadObject
0087: private Object currentObject;
0088:
0089: // Used by defaultReadObject
0090: private ObjectStreamClass currentClass;
0091:
0092: // All validations to be executed when the complete graph is read. See inner
0093: // type below.
0094: private InputValidationDesc[] validations;
0095:
0096: // Allows the receiver to decide if it needs to call readObjectOverride
0097: private boolean subclassOverridingImplementation;
0098:
0099: // Original caller's class loader, used to perform class lookups
0100: private ClassLoader callerClassLoader;
0101:
0102: // false when reading missing fields
0103: private boolean mustResolve = true;
0104:
0105: // Handle for the current class descriptor
0106: private Integer descriptorHandle;
0107:
0108: private static final Hashtable<String, Class<?>> PRIMITIVE_CLASSES = new Hashtable<String, Class<?>>();
0109:
0110: static {
0111: PRIMITIVE_CLASSES.put("byte", byte.class); //$NON-NLS-1$
0112: PRIMITIVE_CLASSES.put("short", short.class); //$NON-NLS-1$
0113: PRIMITIVE_CLASSES.put("int", int.class); //$NON-NLS-1$
0114: PRIMITIVE_CLASSES.put("long", long.class); //$NON-NLS-1$
0115: PRIMITIVE_CLASSES.put("boolean", boolean.class); //$NON-NLS-1$
0116: PRIMITIVE_CLASSES.put("char", char.class); //$NON-NLS-1$
0117: PRIMITIVE_CLASSES.put("float", float.class); //$NON-NLS-1$
0118: PRIMITIVE_CLASSES.put("double", double.class); //$NON-NLS-1$
0119: }
0120:
0121: // Internal type used to keep track of validators & corresponding priority
0122: static class InputValidationDesc {
0123: ObjectInputValidation validator;
0124:
0125: int priority;
0126: }
0127:
0128: /**
0129: * Inner class to provide access to serializable fields
0130: */
0131: public abstract static class GetField {
0132: /**
0133: * @return ObjectStreamClass
0134: */
0135: public abstract ObjectStreamClass getObjectStreamClass();
0136:
0137: /**
0138: * @param name
0139: * @return <code>true</code> if the default value is set,
0140: * <code>false</code> otherwise
0141: *
0142: * @throws IOException
0143: * @throws IllegalArgumentException
0144: */
0145: public abstract boolean defaulted(String name)
0146: throws IOException, IllegalArgumentException;
0147:
0148: /**
0149: * @param name
0150: * @param defaultValue
0151: * @return the value
0152: *
0153: * @throws IOException
0154: * @throws IllegalArgumentException
0155: */
0156: public abstract boolean get(String name, boolean defaultValue)
0157: throws IOException, IllegalArgumentException;
0158:
0159: /**
0160: * @param name
0161: * @param defaultValue
0162: * @return the value
0163: *
0164: * @throws IOException
0165: * @throws IllegalArgumentException
0166: */
0167: public abstract char get(String name, char defaultValue)
0168: throws IOException, IllegalArgumentException;
0169:
0170: /**
0171: * @param name
0172: * @param defaultValue
0173: * @return the value
0174: *
0175: * @throws IOException
0176: * @throws IllegalArgumentException
0177: */
0178: public abstract byte get(String name, byte defaultValue)
0179: throws IOException, IllegalArgumentException;
0180:
0181: /**
0182: * @param name
0183: * @param defaultValue
0184: * @return the value
0185: *
0186: * @throws IOException
0187: * @throws IllegalArgumentException
0188: */
0189: public abstract short get(String name, short defaultValue)
0190: throws IOException, IllegalArgumentException;
0191:
0192: /**
0193: * @param name
0194: * @param defaultValue
0195: * @return the value
0196: *
0197: * @throws IOException
0198: * @throws IllegalArgumentException
0199: */
0200: public abstract int get(String name, int defaultValue)
0201: throws IOException, IllegalArgumentException;
0202:
0203: /**
0204: * @param name
0205: * @param defaultValue
0206: * @return the value
0207: *
0208: * @throws IOException
0209: * @throws IllegalArgumentException
0210: */
0211: public abstract long get(String name, long defaultValue)
0212: throws IOException, IllegalArgumentException;
0213:
0214: /**
0215: * @param name
0216: * @param defaultValue
0217: * @return the value
0218: *
0219: * @throws IOException
0220: * @throws IllegalArgumentException
0221: */
0222: public abstract float get(String name, float defaultValue)
0223: throws IOException, IllegalArgumentException;
0224:
0225: /**
0226: * @param name
0227: * @param defaultValue
0228: * @return the value
0229: *
0230: * @throws IOException
0231: * @throws IllegalArgumentException
0232: */
0233: public abstract double get(String name, double defaultValue)
0234: throws IOException, IllegalArgumentException;
0235:
0236: /**
0237: * @param name
0238: * @param defaultValue
0239: * @return the value
0240: *
0241: * @throws IOException
0242: * @throws IllegalArgumentException
0243: */
0244: public abstract Object get(String name, Object defaultValue)
0245: throws IOException, IllegalArgumentException;
0246: }
0247:
0248: /**
0249: * Constructs a new ObjectInputStream. The representation and proper
0250: * initialization is on the hands of subclasses.
0251: *
0252: * @throws IOException
0253: * If not called from a subclass
0254: * @throws SecurityException
0255: * If subclasses are not allowed
0256: *
0257: * @see SecurityManager#checkPermission(java.security.Permission)
0258: */
0259: protected ObjectInputStream() throws IOException, SecurityException {
0260: super ();
0261: SecurityManager currentManager = System.getSecurityManager();
0262: if (currentManager != null) {
0263: currentManager
0264: .checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
0265: }
0266: // WARNING - we should throw IOException if not called from a subclass
0267: // according to the JavaDoc. Add the test.
0268: this .subclassOverridingImplementation = true;
0269: }
0270:
0271: /**
0272: * Constructs a new ObjectInputStream on the InputStream <code>input</code>.
0273: * All reads are now filtered through this stream.
0274: *
0275: * @param input
0276: * The non-null InputStream to filter reads on.
0277: *
0278: * @throws IOException
0279: * If an IO exception happened when reading the stream header.
0280: * @throws StreamCorruptedException
0281: * If the underlying stream does not contain serialized objects
0282: * that can be read.
0283: */
0284: public ObjectInputStream(InputStream input)
0285: throws StreamCorruptedException, IOException {
0286: final Class<?> implementationClass = getClass();
0287: final Class<?> this Class = ObjectInputStream.class;
0288: SecurityManager sm = System.getSecurityManager();
0289: if (sm != null && implementationClass != this Class) {
0290: boolean mustCheck = (AccessController
0291: .doPrivileged(new PrivilegedAction<Boolean>() {
0292: public Boolean run() {
0293: try {
0294: Method method = implementationClass
0295: .getMethod(
0296: "readFields", //$NON-NLS-1$
0297: ObjectStreamClass.EMPTY_CONSTRUCTOR_PARAM_TYPES);
0298: if (method.getDeclaringClass() != this Class) {
0299: return Boolean.TRUE;
0300: }
0301: } catch (NoSuchMethodException e) {
0302: }
0303: try {
0304: Method method = implementationClass
0305: .getMethod(
0306: "readUnshared", //$NON-NLS-1$
0307: ObjectStreamClass.EMPTY_CONSTRUCTOR_PARAM_TYPES);
0308: if (method.getDeclaringClass() != this Class) {
0309: return Boolean.TRUE;
0310: }
0311: } catch (NoSuchMethodException e) {
0312: }
0313: return Boolean.FALSE;
0314: }
0315: })).booleanValue();
0316: if (mustCheck) {
0317: sm
0318: .checkPermission(ObjectStreamConstants.SUBCLASS_IMPLEMENTATION_PERMISSION);
0319: }
0320: }
0321: this .input = (input instanceof DataInputStream) ? (DataInputStream) input
0322: : new DataInputStream(input);
0323: primitiveTypes = new DataInputStream(this );
0324: enableResolve = false;
0325: this .subclassOverridingImplementation = false;
0326: resetState();
0327: nestedLevels = 0;
0328: // So read...() methods can be used by
0329: // subclasses during readStreamHeader()
0330: primitiveData = this .input;
0331: // Has to be done here according to the specification
0332: readStreamHeader();
0333: primitiveData = emptyStream;
0334: }
0335:
0336: /**
0337: * Returns the number of bytes of primitive data available from the
0338: * receiver. It should not be used at any arbitrary position; just when
0339: * reading primitive data types (ints, chars, etc).
0340: *
0341: * @return the number of available primitive data bytes
0342: *
0343: * @throws IOException
0344: * If any IO problem occurred when trying to compute the bytes
0345: * available.
0346: */
0347: @Override
0348: public int available() throws IOException {
0349: // returns 0 if next data is an object, or N if reading primitive types
0350: checkReadPrimitiveTypes();
0351: return primitiveData.available();
0352: }
0353:
0354: /**
0355: * Checks to see if it is ok to read primitive types at this point from the
0356: * receiver. One is not supposed to read primitive types when about to read
0357: * an object, for example, so an exception has to be thrown.
0358: *
0359: * @throws IOException
0360: * If any IO problem occurred when trying to read primitive type
0361: * or if it is illegal to read primitive types
0362: */
0363: private void checkReadPrimitiveTypes() throws IOException {
0364: // If we still have primitive data, it is ok to read primitive data
0365: if (primitiveData == input || primitiveData.available() > 0) {
0366: return;
0367: }
0368:
0369: // If we got here either we had no Stream previously created or
0370: // we no longer have data in that one, so get more bytes
0371: do {
0372: int next = 0;
0373: if (hasPushbackTC) {
0374: hasPushbackTC = false;
0375: } else {
0376: next = input.read();
0377: pushbackTC = (byte) next;
0378: }
0379: switch (pushbackTC) {
0380: case TC_BLOCKDATA:
0381: primitiveData = new ByteArrayInputStream(
0382: readBlockData());
0383: return;
0384: case TC_BLOCKDATALONG:
0385: primitiveData = new ByteArrayInputStream(
0386: readBlockDataLong());
0387: return;
0388: case TC_RESET:
0389: resetState();
0390: break;
0391: default:
0392: if (next != -1) {
0393: pushbackTC();
0394: }
0395: return;
0396: }
0397: // Only TC_RESET falls through
0398: } while (true);
0399: }
0400:
0401: /**
0402: * Close this ObjectInputStream. This implementation closes the target
0403: * stream.
0404: *
0405: * @throws IOException
0406: * If an error occurs attempting to close this stream.
0407: */
0408: @Override
0409: public void close() throws IOException {
0410: input.close();
0411: }
0412:
0413: /**
0414: * Default method to read objects from the receiver. Fields defined in the
0415: * object's class and super classes (which are Serializable) will be read.
0416: *
0417: * @throws IOException
0418: * If an IO error occurs attempting to read the object data
0419: * @throws ClassNotFoundException
0420: * If the class of the object cannot be found
0421: * @throws NotActiveException
0422: * If this method is not called from readObject()
0423: *
0424: * @see ObjectOutputStream#defaultWriteObject
0425: */
0426: public void defaultReadObject() throws IOException,
0427: ClassNotFoundException, NotActiveException {
0428: // We can't be called from just anywhere. There are rules.
0429: if (currentObject != null || !mustResolve) {
0430: readFieldValues(currentObject, currentClass);
0431: } else {
0432: throw new NotActiveException();
0433: }
0434: }
0435:
0436: /**
0437: * Enables/disables object replacement for the receiver. By default this is
0438: * not enabled. Only trusted subclasses (loaded with system class loader)
0439: * can override this behavior.
0440: *
0441: * @param enable
0442: * if true, enables replacement. If false, disables replacement.
0443: * @return the previous configuration (if it was enabled or disabled)
0444: *
0445: * @throws SecurityException
0446: * If the class of the receiver is not trusted
0447: *
0448: * @see #resolveObject
0449: * @see ObjectOutputStream#enableReplaceObject
0450: */
0451: protected boolean enableResolveObject(boolean enable)
0452: throws SecurityException {
0453: if (enable) {
0454: // The Stream has to be trusted for this feature to be enabled.
0455: // trusted means the stream's classloader has to be null
0456: SecurityManager currentManager = System
0457: .getSecurityManager();
0458: if (currentManager != null) {
0459: currentManager.checkPermission(SUBSTITUTION_PERMISSION);
0460: }
0461: }
0462: boolean originalValue = enableResolve;
0463: enableResolve = enable;
0464: return originalValue;
0465: }
0466:
0467: /**
0468: * Checks if two classes belong to the same package and returns true in the
0469: * positive case. Return false otherwise.
0470: *
0471: * @param c1
0472: * one of the classes to test
0473: * @param c2
0474: * the other class to test
0475: * @return <code>true</code> if the two classes belong to the same
0476: * package, <code>false</code> otherwise
0477: */
0478: private boolean inSamePackage(Class<?> c1, Class<?> c2) {
0479: String nameC1 = c1.getName();
0480: String nameC2 = c2.getName();
0481: int indexDotC1 = nameC1.lastIndexOf('.');
0482: int indexDotC2 = nameC2.lastIndexOf('.');
0483: if (indexDotC1 != indexDotC2) {
0484: return false; // cannot be in the same package if indices are not
0485: }
0486: // the same
0487: if (indexDotC1 < 0) {
0488: return true; // both of them are in default package
0489: }
0490: return nameC1.substring(0, indexDotC1).equals(
0491: nameC2.substring(0, indexDotC2));
0492: }
0493:
0494: /**
0495: * Create and return a new instance of class <code>instantiationClass</code>
0496: * but running the constructor defined in class
0497: * <code>constructorClass</code> (same as <code>instantiationClass</code>
0498: * or a superclass).
0499: *
0500: * Has to be native to avoid visibility rules and to be able to have
0501: * <code>instantiationClass</code> not the same as
0502: * <code>constructorClass</code> (no such API in java.lang.reflect).
0503: *
0504: * @param instantiationClass
0505: * The new object will be an instance of this class
0506: * @param constructorClass
0507: * The empty constructor to run will be in this class
0508: * @return the object created from <code>instantiationClass</code>
0509: */
0510: private static native Object newInstance(
0511: Class<?> instantiationClass, Class<?> constructorClass);
0512:
0513: /**
0514: * Return the next <code>int</code> handle to be used to indicate cyclic
0515: * references being loaded from the stream.
0516: *
0517: * @return the next handle to represent the next cyclic reference
0518: */
0519: private int nextHandle() {
0520: return this .currentHandle++;
0521: }
0522:
0523: /**
0524: * Return the next token code (TC) from the receiver, which indicates what
0525: * kind of object follows
0526: *
0527: * @return the next TC from the receiver
0528: *
0529: * @throws IOException
0530: * If an IO error occurs
0531: *
0532: * @see ObjectStreamConstants
0533: */
0534: private byte nextTC() throws IOException {
0535: if (hasPushbackTC) {
0536: hasPushbackTC = false; // We are consuming it
0537: } else {
0538: // Just in case a later call decides to really push it back,
0539: // we don't require the caller to pass it as parameter
0540: pushbackTC = input.readByte();
0541: }
0542: return pushbackTC;
0543: }
0544:
0545: /**
0546: * Pushes back the last TC code read
0547: */
0548: private void pushbackTC() {
0549: hasPushbackTC = true;
0550: }
0551:
0552: /**
0553: * Reads a single byte from the receiver and returns the result as an int.
0554: * The low-order byte is returned or -1 of the end of stream was
0555: * encountered.
0556: *
0557: * @return The byte read or -1 if end of stream.
0558: *
0559: * @throws IOException
0560: * If an IO exception happened when reading the primitive data.
0561: */
0562: @Override
0563: public int read() throws IOException {
0564: checkReadPrimitiveTypes();
0565: return primitiveData.read();
0566: }
0567:
0568: /**
0569: * Reads at most <code>length</code> bytes from the receiver and stores
0570: * them in byte array <code>buffer</code> starting at offset
0571: * <code>offset</code>. Answer the number of bytes actually read or -1 if
0572: * no bytes were read and end of stream was encountered.
0573: *
0574: * @param buffer
0575: * the byte array in which to store the read bytes.
0576: * @param offset
0577: * the offset in <code>buffer</code> to store the read bytes.
0578: * @param length
0579: * the maximum number of bytes to store in <code>buffer</code>.
0580: * @return The number of bytes actually read or -1 if end of stream.
0581: *
0582: * @throws IOException
0583: * If an IO exception happened when reading the primitive data.
0584: */
0585: @Override
0586: public int read(byte[] buffer, int offset, int length)
0587: throws IOException {
0588: if (buffer == null) {
0589: throw new NullPointerException();
0590: }
0591: // avoid int overflow
0592: if (offset < 0 || offset > buffer.length || length < 0
0593: || length > buffer.length - offset) {
0594: throw new ArrayIndexOutOfBoundsException();
0595: }
0596: if (length == 0) {
0597: return 0;
0598: }
0599: checkReadPrimitiveTypes();
0600: return primitiveData.read(buffer, offset, length);
0601: }
0602:
0603: /**
0604: * Reads and returns an array of raw bytes with primitive data. The array
0605: * will have up to 255 bytes. The primitive data will be in the format
0606: * described by <code>DataOutputStream</code>.
0607: *
0608: * @return The primitive data read, as raw bytes
0609: *
0610: * @throws IOException
0611: * If an IO exception happened when reading the primitive data.
0612: */
0613: private byte[] readBlockData() throws IOException {
0614: byte[] result = new byte[input.readByte() & 0xff];
0615: input.readFully(result);
0616: return result;
0617: }
0618:
0619: /**
0620: * Reads and returns an array of raw bytes with primitive data. The array
0621: * will have more than 255 bytes. The primitive data will be in the format
0622: * described by <code>DataOutputStream</code>.
0623: *
0624: * @return The primitive data read, as raw bytes
0625: *
0626: * @throws IOException
0627: * If an IO exception happened when reading the primitive data.
0628: */
0629: private byte[] readBlockDataLong() throws IOException {
0630: byte[] result = new byte[input.readInt()];
0631: input.readFully(result);
0632: return result;
0633: }
0634:
0635: /**
0636: * Reads and returns primitive data of type boolean read from the receiver
0637: *
0638: * @return A boolean saved as primitive data using
0639: * <code>ObjectOutputStream.writeBoolean()</code>
0640: *
0641: * @throws IOException
0642: * If an IO exception happened when reading the primitive data.
0643: */
0644: public boolean readBoolean() throws IOException {
0645: return primitiveTypes.readBoolean();
0646: }
0647:
0648: /**
0649: * Reads and returns primitive data of type byte read from the receiver
0650: *
0651: * @return A byte saved as primitive data using
0652: * <code>ObjectOutputStream.writeByte()</code>
0653: *
0654: * @throws IOException
0655: * If an IO exception happened when reading the primitive data.
0656: */
0657: public byte readByte() throws IOException {
0658: return primitiveTypes.readByte();
0659: }
0660:
0661: /**
0662: * Reads and returns primitive data of type char read from the receiver
0663: *
0664: * @return A char saved as primitive data using
0665: * <code>ObjectOutputStream.writeChar()</code>
0666: *
0667: * @throws IOException
0668: * If an IO exception happened when reading the primitive data.
0669: */
0670: public char readChar() throws IOException {
0671: return primitiveTypes.readChar();
0672: }
0673:
0674: /**
0675: * Reads and discards block data and objects until TC_ENDBLOCKDATA is found.
0676: *
0677: * @throws IOException
0678: * If an IO exception happened when reading the optional class
0679: * annotation.
0680: * @throws ClassNotFoundException
0681: * If the class corresponding to the class descriptor could not
0682: * be found.
0683: */
0684: private void discardData() throws ClassNotFoundException,
0685: IOException {
0686: primitiveData = emptyStream;
0687: boolean resolve = mustResolve;
0688: mustResolve = false;
0689: do {
0690: byte tc = nextTC();
0691: if (tc == TC_ENDBLOCKDATA) {
0692: mustResolve = resolve;
0693: return; // End of annotation
0694: }
0695: readContent(tc);
0696: } while (true);
0697: }
0698:
0699: /**
0700: * Reads a class descriptor (an <code>ObjectStreamClass</code>) from the
0701: * stream.
0702: *
0703: * @return the class descriptor read from the stream
0704: *
0705: * @throws IOException
0706: * If an IO exception happened when reading the class
0707: * descriptor.
0708: * @throws ClassNotFoundException
0709: * If the class corresponding to the class descriptor could not
0710: * be found.
0711: */
0712: private ObjectStreamClass readClassDesc()
0713: throws ClassNotFoundException, IOException {
0714: byte tc = nextTC();
0715: switch (tc) {
0716: case TC_CLASSDESC:
0717: return readNewClassDesc(false);
0718: case TC_PROXYCLASSDESC:
0719: Class<?> proxyClass = readNewProxyClassDesc();
0720: ObjectStreamClass streamClass = ObjectStreamClass
0721: .lookup(proxyClass);
0722: streamClass.setLoadFields(new ObjectStreamField[0]);
0723: registerObjectRead(streamClass, Integer
0724: .valueOf(nextHandle()), false);
0725: checkedSetSuperClassDesc(streamClass, readClassDesc());
0726: return streamClass;
0727: case TC_REFERENCE:
0728: return (ObjectStreamClass) readCyclicReference();
0729: case TC_NULL:
0730: return null;
0731: default:
0732: throw new StreamCorruptedException(Msg.getString(
0733: "K00d2", Integer.toHexString(tc & 0xff))); //$NON-NLS-1$
0734: }
0735: }
0736:
0737: /**
0738: * Reads the content of the receiver based on the previously read token
0739: * <code>tc</code>.
0740: *
0741: * @param tc
0742: * The token code for the next item in the stream
0743: * @return the object read from the stream
0744: *
0745: * @throws IOException
0746: * If an IO exception happened when reading the class
0747: * descriptor.
0748: * @throws ClassNotFoundException
0749: * If the class corresponding to the object being read could not
0750: * be found.
0751: */
0752: private Object readContent(byte tc) throws ClassNotFoundException,
0753: IOException {
0754: switch (tc) {
0755: case TC_BLOCKDATA:
0756: return readBlockData();
0757: case TC_BLOCKDATALONG:
0758: return readBlockDataLong();
0759: case TC_CLASS:
0760: return readNewClass(false);
0761: case TC_CLASSDESC:
0762: return readNewClassDesc(false);
0763: case TC_ARRAY:
0764: return readNewArray(false);
0765: case TC_OBJECT:
0766: return readNewObject(false);
0767: case TC_STRING:
0768: return readNewString(false);
0769: case TC_LONGSTRING:
0770: return readNewLongString(false);
0771: case TC_REFERENCE:
0772: return readCyclicReference();
0773: case TC_NULL:
0774: return null;
0775: case TC_EXCEPTION:
0776: Exception exc = readException();
0777: throw new WriteAbortedException(Msg.getString("K00d3"), exc); //$NON-NLS-1$
0778: case TC_RESET:
0779: resetState();
0780: return null;
0781: default:
0782: throw new StreamCorruptedException(Msg.getString(
0783: "K00d2", Integer.toHexString(tc & 0xff))); //$NON-NLS-1$
0784: }
0785: }
0786:
0787: /**
0788: * Reads the content of the receiver based on the previously read token
0789: * <code>tc</code>. Primitive data content is considered an error.
0790: *
0791: * @param unshared
0792: * read the object unshared
0793: * @return the object read from the stream
0794: *
0795: * @throws IOException
0796: * If an IO exception happened when reading the class
0797: * descriptor.
0798: * @throws ClassNotFoundException
0799: * If the class corresponding to the object being read could not
0800: * be found.
0801: */
0802: private Object readNonPrimitiveContent(boolean unshared)
0803: throws ClassNotFoundException, IOException {
0804: checkReadPrimitiveTypes();
0805: if (primitiveData.available() > 0) {
0806: OptionalDataException e = new OptionalDataException();
0807: e.length = primitiveData.available();
0808: throw e;
0809: }
0810:
0811: do {
0812: byte tc = nextTC();
0813: switch (tc) {
0814: case TC_CLASS:
0815: return readNewClass(unshared);
0816: case TC_CLASSDESC:
0817: return readNewClassDesc(unshared);
0818: case TC_ARRAY:
0819: return readNewArray(unshared);
0820: case TC_OBJECT:
0821: return readNewObject(unshared);
0822: case TC_STRING:
0823: return readNewString(unshared);
0824: case TC_LONGSTRING:
0825: return readNewLongString(unshared);
0826: case TC_ENUM:
0827: return readEnum(unshared);
0828: case TC_REFERENCE:
0829: if (unshared) {
0830: readNewHandle();
0831: throw new InvalidObjectException(Msg
0832: .getString("KA002")); //$NON-NLS-1$
0833: }
0834: return readCyclicReference();
0835: case TC_NULL:
0836: return null;
0837: case TC_EXCEPTION:
0838: Exception exc = readException();
0839: throw new WriteAbortedException(
0840: Msg.getString("K00d3"), exc); //$NON-NLS-1$
0841: case TC_RESET:
0842: resetState();
0843: break;
0844: case TC_ENDBLOCKDATA: // Can occur reading class annotation
0845: pushbackTC();
0846: OptionalDataException e = new OptionalDataException();
0847: e.eof = true;
0848: throw e;
0849: default:
0850: throw new StreamCorruptedException(Msg.getString(
0851: "K00d2", Integer.toHexString(tc & 0xff))); //$NON-NLS-1$
0852: }
0853: // Only TC_RESET falls through
0854: } while (true);
0855: }
0856:
0857: /**
0858: * Reads the next item from the stream assuming it is a cyclic reference to
0859: * an object previously read. Return the actual object previously read.
0860: *
0861: * @return the object previously read from the stream
0862: *
0863: * @throws IOException
0864: * If an IO exception happened when reading the class
0865: * descriptor.
0866: * @throws InvalidObjectException
0867: * If the cyclic reference is not valid.
0868: */
0869: private Object readCyclicReference() throws InvalidObjectException,
0870: IOException {
0871: return registeredObjectRead(readNewHandle());
0872: }
0873:
0874: /**
0875: * Reads and returns primitive data of type double read from the receiver
0876: *
0877: * @return A double saved as primitive data using
0878: * <code>ObjectOutputStream.writeDouble()</code>
0879: *
0880: * @throws IOException
0881: * If an IO exception happened when reading the primitive data.
0882: */
0883: public double readDouble() throws IOException {
0884: return primitiveTypes.readDouble();
0885: }
0886:
0887: /**
0888: * Read the next item assuming it is an exception. The exception is not a
0889: * regular instance in the object graph, but the exception instance that
0890: * happened (if any) when dumping the original object graph. The set of seen
0891: * objects will be reset just before and just after loading this exception
0892: * object.
0893: * <p>
0894: * When exceptions are found normally in the object graph, they are loaded
0895: * as a regular object, and not by this method. In that case, the set of
0896: * "known objects" is not reset.
0897: *
0898: * @return the exception read
0899: *
0900: * @throws IOException
0901: * If an IO exception happened when reading the exception
0902: * object.
0903: * @throws ClassNotFoundException
0904: * If a class could not be found when reading the object graph
0905: * for the exception
0906: * @throws OptionalDataException
0907: * If optional data could not be found when reading the
0908: * exception graph
0909: * @throws WriteAbortedException
0910: * If another exception was caused when dumping this exception
0911: */
0912: private Exception readException() throws WriteAbortedException,
0913: OptionalDataException, ClassNotFoundException, IOException {
0914:
0915: resetSeenObjects();
0916:
0917: // Now we read the Throwable object that was saved
0918: // WARNING - the grammar says it is a Throwable, but the
0919: // WriteAbortedException constructor takes an Exception. So, we read an
0920: // Exception from the stream
0921: Exception exc = (Exception) readObject();
0922:
0923: // We reset the receiver's state (the grammar has "reset" in normal
0924: // font)
0925: resetSeenObjects();
0926: return exc;
0927: }
0928:
0929: /**
0930: * Reads a collection of field descriptors (name, type name, etc) for the
0931: * class descriptor <code>cDesc</code> (an <code>ObjectStreamClass</code>)
0932: *
0933: * @param cDesc
0934: * The class descriptor (an <code>ObjectStreamClass</code>)
0935: * for which to write field information
0936: *
0937: * @throws IOException
0938: * If an IO exception happened when reading the field
0939: * descriptors.
0940: * @throws ClassNotFoundException
0941: * If a class for one of the field types could not be found
0942: *
0943: * @see #readObject()
0944: */
0945: private void readFieldDescriptors(ObjectStreamClass cDesc)
0946: throws ClassNotFoundException, IOException {
0947: short numFields = input.readShort();
0948: ObjectStreamField[] fields = new ObjectStreamField[numFields];
0949:
0950: // We set it now, but each element will be inserted in the array further
0951: // down
0952: cDesc.setLoadFields(fields);
0953:
0954: // Check ObjectOutputStream.writeFieldDescriptors
0955: for (short i = 0; i < numFields; i++) {
0956: char typecode = (char) input.readByte();
0957: String fieldName = input.readUTF();
0958: boolean isPrimType = ObjectStreamClass
0959: .isPrimitiveType(typecode);
0960: String classSig;
0961: if (isPrimType) {
0962: classSig = String.valueOf(typecode);
0963: } else {
0964: // The spec says it is a UTF, but experience shows they dump
0965: // this String using writeObject (unlike the field name, which
0966: // is saved with writeUTF).
0967: // And if resolveObject is enabled, the classSig may be modified
0968: // so that the original class descriptor cannot be read
0969: // properly, so it is disabled.
0970: boolean old = enableResolve;
0971: try {
0972: enableResolve = false;
0973: classSig = (String) readObject();
0974: } finally {
0975: enableResolve = old;
0976: }
0977: }
0978:
0979: classSig = formatClassSig(classSig);
0980: ObjectStreamField f = new ObjectStreamField(classSig,
0981: fieldName);
0982: fields[i] = f;
0983: }
0984: }
0985:
0986: /*
0987: * Format the class signature for ObjectStreamField, for example,
0988: * "[L[Ljava.lang.String;;" is converted to "[Ljava.lang.String;"
0989: */
0990: private static String formatClassSig(String classSig) {
0991: int start = 0;
0992: int end = classSig.length();
0993:
0994: if (end <= 0) {
0995: return classSig;
0996: }
0997:
0998: while (classSig.startsWith("[L", start) //$NON-NLS-1$
0999: && classSig.charAt(end - 1) == ';') {
1000: start += 2;
1001: end--;
1002: }
1003:
1004: if (start > 0) {
1005: start -= 2;
1006: end++;
1007: return classSig.substring(start, end);
1008: }
1009: return classSig;
1010: }
1011:
1012: /**
1013: * Reads the fields of the object being read from the stream. The stream
1014: * will use the currently active <code>getField</code> object, allowing
1015: * users to load emulated fields, for cross-loading compatibility when a
1016: * class definition changes.
1017: *
1018: * @return the fields being read
1019: *
1020: * @throws IOException
1021: * If an IO exception happened
1022: * @throws ClassNotFoundException
1023: * If a class of an object being de-serialized can not be found
1024: * @throws NotActiveException
1025: * If there is no object currently being loaded (invalid to call
1026: * this method)
1027: */
1028: public GetField readFields() throws IOException,
1029: ClassNotFoundException, NotActiveException {
1030: // We can't be called from just anywhere. There are rules.
1031: if (currentObject == null) {
1032: throw new NotActiveException();
1033: }
1034: EmulatedFieldsForLoading result = new EmulatedFieldsForLoading(
1035: currentClass);
1036: readFieldValues(result);
1037: return result;
1038: }
1039:
1040: /**
1041: * Reads a collection of field values for the emulated fields
1042: * <code>emulatedFields</code>
1043: *
1044: * @param emulatedFields
1045: * an <code>EmulatedFieldsForLoading</code>, concrete subclass
1046: * of <code>GetField</code>
1047: *
1048: * @throws IOException
1049: * If an IO exception happened when reading the field values.
1050: * @throws InvalidClassException
1051: * If an incompatible type is being assigned to an emulated
1052: * field.
1053: * @throws OptionalDataException
1054: * If optional data could not be found when reading the
1055: * exception graph
1056: *
1057: * @see #readFields
1058: * @see #readObject()
1059: */
1060: private void readFieldValues(EmulatedFieldsForLoading emulatedFields)
1061: throws OptionalDataException, InvalidClassException,
1062: IOException {
1063: EmulatedFields.ObjectSlot[] slots = emulatedFields
1064: .emulatedFields().slots();
1065: for (ObjectSlot element : slots) {
1066: element.defaulted = false;
1067: Class<?> type = element.field.getType();
1068: if (type == Integer.TYPE) {
1069: element.fieldValue = Integer.valueOf(input.readInt());
1070: } else if (type == Byte.TYPE) {
1071: element.fieldValue = Byte.valueOf(input.readByte());
1072: } else if (type == Character.TYPE) {
1073: element.fieldValue = Character
1074: .valueOf(input.readChar());
1075: } else if (type == Short.TYPE) {
1076: element.fieldValue = Short.valueOf(input.readShort());
1077: } else if (type == Boolean.TYPE) {
1078: element.fieldValue = Boolean.valueOf(input
1079: .readBoolean());
1080: } else if (type == Long.TYPE) {
1081: element.fieldValue = Long.valueOf(input.readLong());
1082: } else if (type == Float.TYPE) {
1083: element.fieldValue = Float.valueOf(input.readFloat());
1084: } else if (type == Double.TYPE) {
1085: element.fieldValue = Double.valueOf(input.readDouble());
1086: } else {
1087: // Either array or Object
1088: try {
1089: element.fieldValue = readObject();
1090: } catch (ClassNotFoundException cnf) {
1091: // WARNING- Not sure this is the right thing to do. Write
1092: // test case.
1093: throw new InvalidClassException(cnf.toString());
1094: }
1095: }
1096: }
1097: }
1098:
1099: /**
1100: * Reads a collection of field values for the class descriptor
1101: * <code>classDesc</code> (an <code>ObjectStreamClass</code>). The
1102: * values will be used to set instance fields in object <code>obj</code>.
1103: * This is the default mechanism, when emulated fields (an
1104: * <code>GetField</code>) are not used. Actual values to load are stored
1105: * directly into the object <code>obj</code>.
1106: *
1107: * @param obj
1108: * Instance in which the fields will be set.
1109: * @param classDesc
1110: * A class descriptor (an <code>ObjectStreamClass</code>)
1111: * defining which fields should be loaded.
1112: *
1113: * @throws IOException
1114: * If an IO exception happened when reading the field values.
1115: * @throws InvalidClassException
1116: * If an incompatible type is being assigned to an emulated
1117: * field.
1118: * @throws OptionalDataException
1119: * If optional data could not be found when reading the
1120: * exception graph
1121: * @throws ClassNotFoundException
1122: * If a class of an object being de-serialized can not be found
1123: *
1124: * @see #readFields
1125: * @see #readObject()
1126: */
1127: private void readFieldValues(Object obj, ObjectStreamClass classDesc)
1128: throws OptionalDataException, ClassNotFoundException,
1129: IOException {
1130: // Now we must read all fields and assign them to the receiver
1131: ObjectStreamField[] fields = classDesc.getLoadFields();
1132: fields = (null == fields ? new ObjectStreamField[] {} : fields);
1133: Class<?> declaringClass = classDesc.forClass();
1134: if (declaringClass == null && mustResolve) {
1135: throw new ClassNotFoundException(classDesc.getName());
1136: }
1137:
1138: for (ObjectStreamField fieldDesc : fields) {
1139: // Code duplication starts, just because Java is typed
1140: if (fieldDesc.isPrimitive()) {
1141: try {
1142: switch (fieldDesc.getTypeCode()) {
1143: case 'B':
1144: setField(obj, declaringClass, fieldDesc
1145: .getName(), input.readByte());
1146: break;
1147: case 'C':
1148: setField(obj, declaringClass, fieldDesc
1149: .getName(), input.readChar());
1150: break;
1151: case 'D':
1152: setField(obj, declaringClass, fieldDesc
1153: .getName(), input.readDouble());
1154: break;
1155: case 'F':
1156: setField(obj, declaringClass, fieldDesc
1157: .getName(), input.readFloat());
1158: break;
1159: case 'I':
1160: setField(obj, declaringClass, fieldDesc
1161: .getName(), input.readInt());
1162: break;
1163: case 'J':
1164: setField(obj, declaringClass, fieldDesc
1165: .getName(), input.readLong());
1166: break;
1167: case 'S':
1168: setField(obj, declaringClass, fieldDesc
1169: .getName(), input.readShort());
1170: break;
1171: case 'Z':
1172: setField(obj, declaringClass, fieldDesc
1173: .getName(), input.readBoolean());
1174: break;
1175: default:
1176: throw new StreamCorruptedException(
1177: Msg
1178: .getString(
1179: "K00d5", fieldDesc.getTypeCode())); //$NON-NLS-1$
1180: }
1181: } catch (NoSuchFieldError err) {
1182: }
1183: } else {
1184: // Object type (array included).
1185: String fieldName = fieldDesc.getName();
1186: boolean setBack = false;
1187: if (mustResolve && fieldDesc == null) {
1188: setBack = true;
1189: mustResolve = false;
1190: }
1191: Object toSet;
1192: if (fieldDesc != null && fieldDesc.isUnshared()) {
1193: toSet = readUnshared();
1194: } else {
1195: toSet = readObject();
1196: }
1197: if (setBack) {
1198: mustResolve = true;
1199: }
1200: if (fieldDesc != null) {
1201: if (toSet != null) {
1202: Class<?> fieldType = fieldDesc.getType();
1203: Class<?> valueType = toSet.getClass();
1204: if (!fieldType.isAssignableFrom(valueType)) {
1205: throw new ClassCastException(Msg.getString(
1206: "K00d4", new String[] { //$NON-NLS-1$
1207: fieldType.toString(),
1208: valueType.toString(),
1209: classDesc.getName() + "." //$NON-NLS-1$
1210: + fieldName }));
1211: }
1212: try {
1213: objSetField(obj, declaringClass, fieldName,
1214: fieldDesc.getTypeString(), toSet);
1215: } catch (NoSuchFieldError e) {
1216: // Ignored
1217: }
1218: }
1219: }
1220: }
1221: }
1222: }
1223:
1224: /**
1225: * Reads and returns primitive data of type float read from the receiver
1226: *
1227: * @return A float saved as primitive data using
1228: * <code>ObjectOutputStream.writeFloat()</code>
1229: *
1230: * @throws IOException
1231: * If an IO exception happened when reading the primitive data.
1232: */
1233: public float readFloat() throws IOException {
1234: return primitiveTypes.readFloat();
1235: }
1236:
1237: /**
1238: * Reads bytes from the receiver into the byte array <code>buffer</code>.
1239: * This method will block until <code>buffer.length</code> number of bytes
1240: * have been read.
1241: *
1242: * @param buffer
1243: * the buffer to read bytes into
1244: *
1245: * @throws IOException
1246: * if a problem occurs reading from this stream.
1247: */
1248: public void readFully(byte[] buffer) throws IOException {
1249: primitiveTypes.readFully(buffer);
1250: }
1251:
1252: /**
1253: * Reads bytes from the receiver into the byte array <code>buffer</code>.
1254: * This method will block until <code>length</code> number of bytes have
1255: * been read.
1256: *
1257: * @param buffer
1258: * the byte array in which to store the read bytes.
1259: * @param offset
1260: * the offset in <code>buffer</code> to store the read bytes.
1261: * @param length
1262: * the maximum number of bytes to store in <code>buffer</code>.
1263: *
1264: * @throws IOException
1265: * if a problem occurs reading from this stream.
1266: */
1267: public void readFully(byte[] buffer, int offset, int length)
1268: throws IOException {
1269: primitiveTypes.readFully(buffer, offset, length);
1270: }
1271:
1272: /**
1273: * Walks the hierarchy of classes described by class descriptor
1274: * <code>classDesc</code> and reads the field values corresponding to
1275: * fields declared by the corresponding class descriptor. The instance to
1276: * store field values into is <code>object</code>. If the class
1277: * (corresponding to class descriptor <code>classDesc</code>) defines
1278: * private instance method <code>readObject</code> it will be used to load
1279: * field values.
1280: *
1281: * @param object
1282: * Instance into which stored field values loaded.
1283: * @param classDesc
1284: * A class descriptor (an <code>ObjectStreamClass</code>)
1285: * defining which fields should be loaded.
1286: *
1287: * @throws IOException
1288: * If an IO exception happened when reading the field values in
1289: * the hierarchy.
1290: * @throws ClassNotFoundException
1291: * If a class for one of the field types could not be found
1292: * @throws NotActiveException
1293: * If <code>defaultReadObject</code> is called from the wrong
1294: * context.
1295: *
1296: * @see #defaultReadObject
1297: * @see #readObject()
1298: */
1299: private void readHierarchy(Object object,
1300: ObjectStreamClass classDesc) throws IOException,
1301: ClassNotFoundException, NotActiveException {
1302: // We can't be called from just anywhere. There are rules.
1303: if (object == null && mustResolve) {
1304: throw new NotActiveException();
1305: }
1306:
1307: ArrayList<ObjectStreamClass> streamClassList = new ArrayList<ObjectStreamClass>(
1308: 32);
1309: ObjectStreamClass nextStreamClass = classDesc;
1310: while (nextStreamClass != null) {
1311: streamClassList.add(0, nextStreamClass);
1312: nextStreamClass = nextStreamClass.getSuperclass();
1313: }
1314: if (object == null) {
1315: Iterator<ObjectStreamClass> streamIt = streamClassList
1316: .iterator();
1317: while (streamIt.hasNext()) {
1318: ObjectStreamClass streamClass = streamIt.next();
1319: readObjectForClass(null, streamClass);
1320: }
1321: } else {
1322: ArrayList<Class<?>> classList = new ArrayList<Class<?>>(32);
1323: Class<?> nextClass = object.getClass();
1324: while (nextClass != null) {
1325: Class<?> testClass = nextClass.getSuperclass();
1326: if (testClass != null) {
1327: classList.add(0, nextClass);
1328: }
1329: nextClass = testClass;
1330: }
1331: int lastIndex = 0;
1332: for (int i = 0; i < classList.size(); i++) {
1333: Class<?> super class = classList.get(i);
1334: int index = findStreamSuperclass(super class,
1335: streamClassList, lastIndex);
1336: if (index == -1) {
1337: readObjectNoData(object, super class);
1338: } else {
1339: for (int j = lastIndex; j <= index; j++) {
1340: readObjectForClass(object, streamClassList
1341: .get(j));
1342: }
1343: lastIndex = index + 1;
1344: }
1345: }
1346: }
1347: }
1348:
1349: private int findStreamSuperclass(Class<?> cl,
1350: ArrayList<ObjectStreamClass> classList, int lastIndex) {
1351: ObjectStreamClass objCl;
1352: String forName;
1353:
1354: for (int i = lastIndex; i < classList.size(); i++) {
1355: objCl = classList.get(i);
1356: forName = objCl.forClass().getName();
1357:
1358: if (objCl.getName().equals(forName)) {
1359: if (cl.getName().equals(objCl.getName())) {
1360: return i;
1361: }
1362: } else {
1363: // there was a class replacement
1364: if (cl.getName().equals(forName)) {
1365: return i;
1366: }
1367: }
1368: }
1369: return -1;
1370: }
1371:
1372: private void readObjectNoData(Object object, Class<?> cl)
1373: throws ObjectStreamException {
1374: if (!ObjectStreamClass.isSerializable(cl)) {
1375: return;
1376: }
1377: ObjectStreamClass classDesc = ObjectStreamClass
1378: .lookupStreamClass(cl);
1379: if (classDesc.hasMethodReadObjectNoData()) {
1380: final Method readMethod = classDesc
1381: .getMethodReadObjectNoData();
1382: try {
1383: readMethod.invoke(object, new Object[0]);
1384: } catch (InvocationTargetException e) {
1385: Throwable ex = e.getTargetException();
1386: if (ex instanceof RuntimeException) {
1387: throw (RuntimeException) ex;
1388: } else if (ex instanceof Error) {
1389: throw (Error) ex;
1390: }
1391: throw (ObjectStreamException) ex;
1392: } catch (IllegalAccessException e) {
1393: throw new RuntimeException(e.toString());
1394: }
1395: }
1396:
1397: }
1398:
1399: private void readObjectForClass(Object object,
1400: ObjectStreamClass classDesc) throws IOException,
1401: ClassNotFoundException, NotActiveException {
1402: // Have to do this before calling defaultReadObject or anything that
1403: // calls defaultReadObject
1404: currentObject = object;
1405: currentClass = classDesc;
1406:
1407: boolean hadWriteMethod = (classDesc.getFlags() & SC_WRITE_METHOD) > 0;
1408: Class<?> targetClass = classDesc.forClass();
1409:
1410: final Method readMethod;
1411: if (targetClass == null || !mustResolve) {
1412: readMethod = null;
1413: } else {
1414: readMethod = classDesc.getMethodReadObject();
1415: }
1416: try {
1417: if (readMethod != null) {
1418: // We have to be able to fetch its value, even if it is private
1419: AccessController.doPrivileged(new PriviAction<Object>(
1420: readMethod));
1421: try {
1422: readMethod.invoke(object, new Object[] { this });
1423: } catch (InvocationTargetException e) {
1424: Throwable ex = e.getTargetException();
1425: if (ex instanceof ClassNotFoundException) {
1426: throw (ClassNotFoundException) ex;
1427: } else if (ex instanceof RuntimeException) {
1428: throw (RuntimeException) ex;
1429: } else if (ex instanceof Error) {
1430: throw (Error) ex;
1431: }
1432: throw (IOException) ex;
1433: } catch (IllegalAccessException e) {
1434: throw new RuntimeException(e.toString());
1435: }
1436: } else {
1437: defaultReadObject();
1438: }
1439: if (hadWriteMethod) {
1440: discardData();
1441: }
1442: } finally {
1443: // Cleanup, needs to run always so that we can later detect invalid
1444: // calls to defaultReadObject
1445: currentObject = null; // We did not set this, so we do not need to
1446: // clean it
1447: currentClass = null;
1448: }
1449: }
1450:
1451: /**
1452: * Reads and returns primitive data of type int read from the receiver
1453: *
1454: * @return an int saved as primitive data using
1455: * <code>ObjectOutputStream.writeInt()</code>
1456: *
1457: * @throws IOException
1458: * If an IO exception happened when reading the primitive data.
1459: */
1460: public int readInt() throws IOException {
1461: return primitiveTypes.readInt();
1462: }
1463:
1464: /**
1465: * Reads and returns the next line (primitive data of type String) read from
1466: * the receiver
1467: *
1468: * @return a String saved as primitive data using
1469: * <code>ObjectOutputStream.writeLine()</code>
1470: *
1471: * @throws IOException
1472: * If an IO exception happened when reading the primitive data.
1473: *
1474: * @deprecated Use BufferedReader
1475: */
1476: @SuppressWarnings("deprecation")
1477: @Deprecated
1478: public String readLine() throws IOException {
1479: return primitiveTypes.readLine();
1480: }
1481:
1482: /**
1483: * Reads and returns primitive data of type long read from the receiver
1484: *
1485: * @return a long saved as primitive data using
1486: * <code>ObjectOutputStream.writeLong()</code>
1487: *
1488: * @throws IOException
1489: * If an IO exception happened when reading the primitive data.
1490: */
1491: public long readLong() throws IOException {
1492: return primitiveTypes.readLong();
1493: }
1494:
1495: /**
1496: * Read a new array from the receiver. It is assumed the array has not been
1497: * read yet (not a cyclic reference). Return the array read.
1498: *
1499: * @param unshared
1500: * read the object unshared
1501: * @return the array read
1502: *
1503: * @throws IOException
1504: * If an IO exception happened when reading the array.
1505: * @throws ClassNotFoundException
1506: * If a class for one of the objects could not be found
1507: * @throws OptionalDataException
1508: * If optional data could not be found when reading the array.
1509: */
1510: private Object readNewArray(boolean unshared)
1511: throws OptionalDataException, ClassNotFoundException,
1512: IOException {
1513: ObjectStreamClass classDesc = readClassDesc();
1514:
1515: if (classDesc == null) {
1516: throw new InvalidClassException(Msg.getString("K00d1")); //$NON-NLS-1$
1517: }
1518:
1519: Integer newHandle = Integer.valueOf(nextHandle());
1520:
1521: // Array size
1522: int size = input.readInt();
1523: Class<?> arrayClass = classDesc.forClass();
1524: Class<?> componentType = arrayClass.getComponentType();
1525: Object result = Array.newInstance(componentType, size);
1526:
1527: registerObjectRead(result, newHandle, unshared);
1528:
1529: // Now we have code duplication just because Java is typed. We have to
1530: // read N elements and assign to array positions, but we must typecast
1531: // the array first, and also call different methods depending on the
1532: // elements.
1533: if (componentType.isPrimitive()) {
1534: if (componentType == Integer.TYPE) {
1535: int[] intArray = (int[]) result;
1536: for (int i = 0; i < size; i++) {
1537: intArray[i] = input.readInt();
1538: }
1539: } else if (componentType == Byte.TYPE) {
1540: byte[] byteArray = (byte[]) result;
1541: input.readFully(byteArray, 0, size);
1542: } else if (componentType == Character.TYPE) {
1543: char[] charArray = (char[]) result;
1544: for (int i = 0; i < size; i++) {
1545: charArray[i] = input.readChar();
1546: }
1547: } else if (componentType == Short.TYPE) {
1548: short[] shortArray = (short[]) result;
1549: for (int i = 0; i < size; i++) {
1550: shortArray[i] = input.readShort();
1551: }
1552: } else if (componentType == Boolean.TYPE) {
1553: boolean[] booleanArray = (boolean[]) result;
1554: for (int i = 0; i < size; i++) {
1555: booleanArray[i] = input.readBoolean();
1556: }
1557: } else if (componentType == Long.TYPE) {
1558: long[] longArray = (long[]) result;
1559: for (int i = 0; i < size; i++) {
1560: longArray[i] = input.readLong();
1561: }
1562: } else if (componentType == Float.TYPE) {
1563: float[] floatArray = (float[]) result;
1564: for (int i = 0; i < size; i++) {
1565: floatArray[i] = input.readFloat();
1566: }
1567: } else if (componentType == Double.TYPE) {
1568: double[] doubleArray = (double[]) result;
1569: for (int i = 0; i < size; i++) {
1570: doubleArray[i] = input.readDouble();
1571: }
1572: } else {
1573: throw new ClassNotFoundException(Msg.getString(
1574: "K00d7", classDesc.getName())); //$NON-NLS-1$
1575: }
1576: } else {
1577: // Array of Objects
1578: Object[] objectArray = (Object[]) result;
1579: for (int i = 0; i < size; i++) {
1580: objectArray[i] = readObject();
1581: }
1582: }
1583: if (enableResolve) {
1584: result = resolveObject(result);
1585: registerObjectRead(result, newHandle, false);
1586: }
1587: return result;
1588: }
1589:
1590: /**
1591: * Reads a new class from the receiver. It is assumed the class has not been
1592: * read yet (not a cyclic reference). Return the class read.
1593: *
1594: * @param unshared
1595: * read the object unshared
1596: * @return The <code>java.lang.Class</code> read from the stream.
1597: *
1598: * @throws IOException
1599: * If an IO exception happened when reading the class.
1600: * @throws ClassNotFoundException
1601: * If a class for one of the objects could not be found
1602: */
1603: private Class<?> readNewClass(boolean unshared)
1604: throws ClassNotFoundException, IOException {
1605: ObjectStreamClass classDesc = readClassDesc();
1606:
1607: if (classDesc != null) {
1608: Integer newHandle = Integer.valueOf(nextHandle());
1609: Class<?> localClass = classDesc.forClass();
1610: if (localClass != null) {
1611: registerObjectRead(localClass, newHandle, unshared);
1612: }
1613: return localClass;
1614: }
1615: throw new InvalidClassException(Msg.getString("K00d1")); //$NON-NLS-1$
1616: }
1617:
1618: /*
1619: * read class type for Enum, note there's difference between enum and normal
1620: * classes
1621: */
1622: private ObjectStreamClass readEnumDesc() throws IOException,
1623: ClassNotFoundException {
1624: byte tc = nextTC();
1625: switch (tc) {
1626: case TC_CLASSDESC:
1627: return readEnumDescInternal();
1628: case TC_REFERENCE:
1629: return (ObjectStreamClass) readCyclicReference();
1630: case TC_NULL:
1631: return null;
1632: default:
1633: throw new StreamCorruptedException(Msg.getString(
1634: "K00d2", Integer.toHexString(tc & 0xff))); //$NON-NLS-1$
1635: }
1636: }
1637:
1638: private ObjectStreamClass readEnumDescInternal()
1639: throws IOException, ClassNotFoundException {
1640: ObjectStreamClass classDesc;
1641: primitiveData = input;
1642: Integer oldHandle = descriptorHandle;
1643: descriptorHandle = Integer.valueOf(nextHandle());
1644: classDesc = readClassDescriptor();
1645: registerObjectRead(classDesc, descriptorHandle, false);
1646: descriptorHandle = oldHandle;
1647: primitiveData = emptyStream;
1648: classDesc.setClass(resolveClass(classDesc));
1649: // Consume unread class annotation data and TC_ENDBLOCKDATA
1650: discardData();
1651: ObjectStreamClass super Class = readClassDesc();
1652: checkedSetSuperClassDesc(classDesc, super Class);
1653: // Check SUIDs, note all SUID for Enum is 0L
1654: if (0L != classDesc.getSerialVersionUID()
1655: || 0L != super Class.getSerialVersionUID()) {
1656: throw new InvalidClassException(super Class.getName(), Msg
1657: .getString("K00da", super Class, //$NON-NLS-1$
1658: super Class));
1659: }
1660: byte tc = nextTC();
1661: // discard TC_ENDBLOCKDATA after classDesc if any
1662: if (tc == TC_ENDBLOCKDATA) {
1663: // read next parent class. For enum, it may be null
1664: super Class.setSuperclass(readClassDesc());
1665: } else {
1666: // not TC_ENDBLOCKDATA, push back for next read
1667: pushbackTC();
1668: }
1669: return classDesc;
1670: }
1671:
1672: @SuppressWarnings("unchecked")
1673: // For the Enum.valueOf call
1674: private Object readEnum(boolean unshared)
1675: throws OptionalDataException, ClassNotFoundException,
1676: IOException {
1677: // read classdesc for Enum first
1678: ObjectStreamClass classDesc = readEnumDesc();
1679: Integer newHandle = Integer.valueOf(nextHandle());
1680: // read name after class desc
1681: String name;
1682: byte tc = nextTC();
1683: switch (tc) {
1684: case TC_REFERENCE:
1685: if (unshared) {
1686: readNewHandle();
1687: throw new InvalidObjectException(Msg.getString("KA002")); //$NON-NLS-1$
1688: }
1689: name = (String) readCyclicReference();
1690: break;
1691: case TC_STRING:
1692: name = (String) readNewString(unshared);
1693: break;
1694: default:
1695: throw new StreamCorruptedException(Msg.getString("K00d2"));//$NON-NLS-1$
1696: }
1697:
1698: Enum<?> result = Enum.valueOf((Class) classDesc.forClass(),
1699: name);
1700: registerObjectRead(result, newHandle, unshared);
1701:
1702: return result;
1703: }
1704:
1705: /**
1706: * Reads a new class descriptor from the receiver. It is assumed the class
1707: * descriptor has not been read yet (not a cyclic reference). Return the
1708: * class descriptor read.
1709: *
1710: * @param unshared
1711: * read the object unshared
1712: * @return The <code>ObjectStreamClass</code> read from the stream.
1713: *
1714: * @throws IOException
1715: * If an IO exception happened when reading the class
1716: * descriptor.
1717: * @throws ClassNotFoundException
1718: * If a class for one of the objects could not be found
1719: */
1720: private ObjectStreamClass readNewClassDesc(boolean unshared)
1721: throws ClassNotFoundException, IOException {
1722: // So read...() methods can be used by
1723: // subclasses during readClassDescriptor()
1724: primitiveData = input;
1725: Integer oldHandle = descriptorHandle;
1726: descriptorHandle = Integer.valueOf(nextHandle());
1727: ObjectStreamClass newClassDesc = readClassDescriptor();
1728: registerObjectRead(newClassDesc, descriptorHandle, unshared);
1729: descriptorHandle = oldHandle;
1730: primitiveData = emptyStream;
1731:
1732: // We need to map classDesc to class.
1733: try {
1734: newClassDesc.setClass(resolveClass(newClassDesc));
1735: // Check SUIDs & base name of the class
1736: verifyAndInit(newClassDesc);
1737: } catch (ClassNotFoundException e) {
1738: if (mustResolve) {
1739: throw e;
1740: // Just continue, the class may not be required
1741: }
1742: }
1743:
1744: // Resolve the field signatures using the class loader of the
1745: // resolved class
1746: ObjectStreamField[] fields = newClassDesc.getLoadFields();
1747: fields = (null == fields ? new ObjectStreamField[] {} : fields);
1748: ClassLoader loader = newClassDesc.forClass() == null ? callerClassLoader
1749: : newClassDesc.forClass().getClassLoader();
1750: for (ObjectStreamField element : fields) {
1751: element.resolve(loader);
1752: }
1753:
1754: // Consume unread class annotation data and TC_ENDBLOCKDATA
1755: discardData();
1756: checkedSetSuperClassDesc(newClassDesc, readClassDesc());
1757: return newClassDesc;
1758: }
1759:
1760: /**
1761: * Reads a new proxy class descriptor from the receiver. It is assumed the
1762: * proxy class descriptor has not been read yet (not a cyclic reference).
1763: * Return the proxy class descriptor read.
1764: *
1765: * @return The <code>Class</code> read from the stream.
1766: *
1767: * @throws IOException
1768: * If an IO exception happened when reading the class
1769: * descriptor.
1770: * @throws ClassNotFoundException
1771: * If a class for one of the objects could not be found
1772: */
1773: private Class<?> readNewProxyClassDesc()
1774: throws ClassNotFoundException, IOException {
1775: int count = input.readInt();
1776: String[] interfaceNames = new String[count];
1777: for (int i = 0; i < count; i++) {
1778: interfaceNames[i] = input.readUTF();
1779: }
1780: Class<?> proxy = resolveProxyClass(interfaceNames);
1781: // Consume unread class annotation data and TC_ENDBLOCKDATA
1782: discardData();
1783: return proxy;
1784: }
1785:
1786: /**
1787: * Reads a new class descriptor from the receiver. Return the class
1788: * descriptor read.
1789: *
1790: * @return The <code>ObjectStreamClass</code> read from the stream.
1791: *
1792: * @throws IOException
1793: * If an IO exception happened when reading the class
1794: * descriptor.
1795: * @throws ClassNotFoundException
1796: * If a class for one of the objects could not be found
1797: */
1798: protected ObjectStreamClass readClassDescriptor()
1799: throws IOException, ClassNotFoundException {
1800:
1801: ObjectStreamClass newClassDesc = new ObjectStreamClass();
1802: String name = input.readUTF();
1803: if (name.length() == 0) {
1804: // luni.07 = The stream is corrupted
1805: throw new IOException(Messages.getString("luni.07")); //$NON-NLS-1$
1806: }
1807: newClassDesc.setName(name);
1808: newClassDesc.setSerialVersionUID(input.readLong());
1809: newClassDesc.setFlags(input.readByte());
1810:
1811: /*
1812: * We must register the class descriptor before reading field
1813: * descriptors. If called outside of readObject, the descriptorHandle
1814: * might be null.
1815: */
1816: descriptorHandle = (null == descriptorHandle ? Integer
1817: .valueOf(nextHandle()) : descriptorHandle);
1818: registerObjectRead(newClassDesc, descriptorHandle, false);
1819:
1820: readFieldDescriptors(newClassDesc);
1821: return newClassDesc;
1822: }
1823:
1824: /**
1825: * Retrieves the proxy class corresponding to the interface names.
1826: *
1827: * @param interfaceNames
1828: * The interfaces used to create the proxy class
1829: * @return A proxy class
1830: *
1831: * @throws IOException
1832: * If any IO problem occurred when trying to load the class.
1833: * @throws ClassNotFoundException
1834: * If the proxy class cannot be created
1835: */
1836: protected Class<?> resolveProxyClass(String[] interfaceNames)
1837: throws IOException, ClassNotFoundException {
1838: ClassLoader loader = VM.getNonBootstrapClassLoader();
1839: Class<?>[] interfaces = new Class<?>[interfaceNames.length];
1840: for (int i = 0; i < interfaceNames.length; i++) {
1841: interfaces[i] = Class.forName(interfaceNames[i], false,
1842: loader);
1843: }
1844: try {
1845: return Proxy.getProxyClass(loader, interfaces);
1846: } catch (IllegalArgumentException e) {
1847: throw new ClassNotFoundException(e.toString(), e);
1848: }
1849: }
1850:
1851: /**
1852: * Write a new handle describing a cyclic reference from the stream.
1853: *
1854: * @return the handle read
1855: *
1856: * @throws IOException
1857: * If an IO exception happened when reading the handle
1858: */
1859: private Integer readNewHandle() throws IOException {
1860: return Integer.valueOf(input.readInt());
1861: }
1862:
1863: /**
1864: * Read a new object from the stream. It is assumed the object has not been
1865: * loaded yet (not a cyclic reference). Return the object read.
1866: *
1867: * If the object implements <code>Externalizable</code> its
1868: * <code>readExternal</code> is called. Otherwise, all fields described by
1869: * the class hierarchy are loaded. Each class can define how its declared
1870: * instance fields are loaded by defining a private method
1871: * <code>readObject</code>
1872: *
1873: * @param unshared
1874: * read the object unshared
1875: * @return the object read
1876: *
1877: * @throws IOException
1878: * If an IO exception happened when reading the object.
1879: * @throws OptionalDataException
1880: * If optional data could not be found when reading the object
1881: * graph
1882: * @throws ClassNotFoundException
1883: * If a class for one of the objects could not be found
1884: */
1885: private Object readNewObject(boolean unshared)
1886: throws OptionalDataException, ClassNotFoundException,
1887: IOException {
1888: ObjectStreamClass classDesc = readClassDesc();
1889:
1890: if (classDesc == null) {
1891: throw new InvalidClassException(Msg.getString("K00d1")); //$NON-NLS-1$
1892: }
1893:
1894: Integer newHandle = Integer.valueOf(nextHandle());
1895:
1896: // Note that these values come from the Stream, and in fact it could be
1897: // that the classes have been changed so that the info below now
1898: // conflicts with the newer class
1899: boolean wasExternalizable = (classDesc.getFlags() & SC_EXTERNALIZABLE) > 0;
1900: boolean wasSerializable = (classDesc.getFlags() & SC_SERIALIZABLE) > 0;
1901:
1902: // Maybe we should cache the values above in classDesc ? It may be the
1903: // case that when reading classDesc we may need to read more stuff
1904: // depending on the values above
1905: Class<?> objectClass = classDesc.forClass();
1906:
1907: Object result, registeredResult = null;
1908: if (objectClass != null) {
1909: // The class of the instance may not be the same as the class of the
1910: // constructor to run
1911: // This is the constructor to run if Externalizable
1912: Class<?> constructorClass = objectClass;
1913:
1914: // WARNING - What if the object is serializable and externalizable ?
1915: // Is that possible ?
1916: if (wasSerializable) {
1917: // Now we must run the constructor of the class just above the
1918: // one that implements Serializable so that slots that were not
1919: // dumped can be initialized properly
1920: while (constructorClass != null
1921: && ObjectStreamClass
1922: .isSerializable(constructorClass)) {
1923: constructorClass = constructorClass.getSuperclass();
1924: }
1925: }
1926:
1927: // Fetch the empty constructor, or null if none.
1928: Constructor<?> constructor = null;
1929: if (constructorClass != null) {
1930: try {
1931: constructor = constructorClass
1932: .getDeclaredConstructor(ObjectStreamClass.EMPTY_CONSTRUCTOR_PARAM_TYPES);
1933: } catch (NoSuchMethodException nsmEx) {
1934: // Ignored
1935: }
1936: }
1937:
1938: // Has to have an empty constructor
1939: if (constructor == null) {
1940: throw new InvalidClassException(constructorClass
1941: .getName(), Msg.getString("K00dc")); //$NON-NLS-1$
1942: }
1943:
1944: int constructorModifiers = constructor.getModifiers();
1945:
1946: // Now we must check if the empty constructor is visible to the
1947: // instantiation class
1948: if (Modifier.isPrivate(constructorModifiers)
1949: || (wasExternalizable && !Modifier
1950: .isPublic(constructorModifiers))) {
1951: throw new InvalidClassException(constructorClass
1952: .getName(), Msg.getString("K00dc")); //$NON-NLS-1$
1953: }
1954:
1955: // We know we are testing from a subclass, so the only other case
1956: // where the visibility is not allowed is when the constructor has
1957: // default visibility and the instantiation class is in a different
1958: // package than the constructor class
1959: if (!Modifier.isPublic(constructorModifiers)
1960: && !Modifier.isProtected(constructorModifiers)) {
1961: // Not public, not private and not protected...means default
1962: // visibility. Check if same package
1963: if (!inSamePackage(constructorClass, objectClass)) {
1964: throw new InvalidClassException(constructorClass
1965: .getName(), Msg.getString("K00dc")); //$NON-NLS-1$
1966: }
1967: }
1968:
1969: // Now we know which class to instantiate and which constructor to
1970: // run. We are allowed to run the constructor.
1971: result = newInstance(objectClass, constructorClass);
1972: registerObjectRead(result, newHandle, unshared);
1973:
1974: registeredResult = result;
1975: } else {
1976: result = null;
1977: }
1978:
1979: try {
1980: // This is how we know what to do in defaultReadObject. And it is
1981: // also used by defaultReadObject to check if it was called from an
1982: // invalid place. It also allows readExternal to call
1983: // defaultReadObject and have it work.
1984: currentObject = result;
1985: currentClass = classDesc;
1986:
1987: // If Externalizable, just let the object read itself
1988: if (wasExternalizable) {
1989: boolean blockData = (classDesc.getFlags() & SC_BLOCK_DATA) > 0;
1990: if (!blockData) {
1991: primitiveData = input;
1992: }
1993: if (mustResolve) {
1994: Externalizable extern = (Externalizable) result;
1995: extern.readExternal(this );
1996: }
1997: if (blockData) {
1998: // Similar to readHierarchy. Anything not read by
1999: // readExternal has to be consumed here
2000: discardData();
2001: } else {
2002: primitiveData = emptyStream;
2003: }
2004: } else {
2005: // If we got here, it is Serializable but not Externalizable.
2006: // Walk the hierarchy reading each class' slots
2007: readHierarchy(result, classDesc);
2008: }
2009: } finally {
2010: // Cleanup, needs to run always so that we can later detect invalid
2011: // calls to defaultReadObject
2012: currentObject = null;
2013: currentClass = null;
2014: }
2015:
2016: if (objectClass != null) {
2017:
2018: ObjectStreamClass desc = ObjectStreamClass
2019: .lookupStreamClass(objectClass);
2020: if (desc.hasMethodReadResolve()) {
2021: Method methodReadResolve = desc.getMethodReadResolve();
2022: try {
2023: result = methodReadResolve.invoke(result,
2024: (Object[]) null);
2025: } catch (IllegalAccessException iae) {
2026: } catch (InvocationTargetException ite) {
2027: Throwable target = ite.getTargetException();
2028: if (target instanceof ObjectStreamException) {
2029: throw (ObjectStreamException) target;
2030: } else if (target instanceof Error) {
2031: throw (Error) target;
2032: } else {
2033: throw (RuntimeException) target;
2034: }
2035: }
2036:
2037: }
2038: }
2039: // We get here either if class-based replacement was not needed or if it
2040: // was needed but produced the same object or if it could not be
2041: // computed.
2042:
2043: // The object to return is the one we instantiated or a replacement for
2044: // it
2045: if (result != null && enableResolve) {
2046: result = resolveObject(result);
2047: }
2048: if (registeredResult != result) {
2049: registerObjectRead(result, newHandle, unshared);
2050: }
2051: return result;
2052: }
2053:
2054: /**
2055: * Read a new String in UTF format from the receiver. Return the string
2056: * read.
2057: *
2058: * @param unshared
2059: * read the object unshared
2060: * @return the string just read.
2061: *
2062: * @throws IOException
2063: * If an IO exception happened when reading the String.
2064: */
2065: private Object readNewString(boolean unshared) throws IOException {
2066: Object result = input.readUTF();
2067: if (enableResolve) {
2068: result = resolveObject(result);
2069: }
2070: int newHandle = nextHandle();
2071: registerObjectRead(result, Integer.valueOf(newHandle), unshared);
2072:
2073: return result;
2074: }
2075:
2076: /**
2077: * Read a new String in UTF format from the receiver. Return the string
2078: * read.
2079: *
2080: * @param unshared
2081: * read the object unshared
2082: * @return the string just read.
2083: *
2084: * @throws IOException
2085: * If an IO exception happened when reading the String.
2086: */
2087: private Object readNewLongString(boolean unshared)
2088: throws IOException {
2089: long length = input.readLong();
2090: Object result = input.decodeUTF((int) length);
2091: if (enableResolve) {
2092: result = resolveObject(result);
2093: }
2094: int newHandle = nextHandle();
2095: registerObjectRead(result, Integer.valueOf(newHandle), unshared);
2096:
2097: return result;
2098: }
2099:
2100: /**
2101: * Read the next object from the receiver's underlying stream.
2102: *
2103: * @return the new object read.
2104: *
2105: * @throws IOException
2106: * If an IO exception happened when reading the object
2107: * @throws ClassNotFoundException
2108: * If the class of one of the objects in the object graph could
2109: * not be found
2110: * @throws OptionalDataException
2111: * If primitive data types were found instead of an object.
2112: *
2113: * @see ObjectOutputStream#writeObject(Object)
2114: */
2115: public final Object readObject() throws OptionalDataException,
2116: ClassNotFoundException, IOException {
2117: return readObject(false);
2118: }
2119:
2120: /**
2121: * Read the next unshared object from the receiver's underlying stream.
2122: *
2123: * @return the new object read.
2124: *
2125: * @throws IOException
2126: * If an IO exception happened when reading the object
2127: * @throws ClassNotFoundException
2128: * If the class of one of the objects in the object graph could
2129: * not be found
2130: *
2131: * @see ObjectOutputStream#writeUnshared
2132: */
2133: public Object readUnshared() throws IOException,
2134: ClassNotFoundException {
2135: return readObject(true);
2136: }
2137:
2138: private Object readObject(boolean unshared)
2139: throws OptionalDataException, ClassNotFoundException,
2140: IOException {
2141: boolean restoreInput = (primitiveData == input);
2142: if (restoreInput) {
2143: primitiveData = emptyStream;
2144: }
2145:
2146: // This is the spec'ed behavior in JDK 1.2. Very bizarre way to allow
2147: // behavior overriding.
2148: if (subclassOverridingImplementation && !unshared) {
2149: return readObjectOverride();
2150: }
2151:
2152: // If we still had primitive types to read, should we discard them
2153: // (reset the primitiveTypes stream) or leave as is, so that attempts to
2154: // read primitive types won't read 'past data' ???
2155: Object result;
2156: try {
2157: // We need this so we can tell when we are returning to the
2158: // original/outside caller
2159: if (++nestedLevels == 1) {
2160: // Remember the caller's class loader
2161: callerClassLoader = VM.getNonBootstrapClassLoader();
2162: }
2163:
2164: result = readNonPrimitiveContent(unshared);
2165: if (restoreInput) {
2166: primitiveData = input;
2167: }
2168: } finally {
2169: // We need this so we can tell when we are returning to the
2170: // original/outside caller
2171: if (--nestedLevels == 0) {
2172: // We are going to return to the original caller, perform
2173: // cleanups.
2174: // No more need to remember the caller's class loader
2175: callerClassLoader = null;
2176: }
2177: }
2178:
2179: // Done reading this object. Is it time to return to the original
2180: // caller? If so we need to perform validations first.
2181: if (nestedLevels == 0 && validations != null) {
2182: // We are going to return to the original caller. If validation is
2183: // enabled we need to run them now and then cleanup the validation
2184: // collection
2185: try {
2186: for (InputValidationDesc element : validations) {
2187: element.validator.validateObject();
2188: }
2189: } finally {
2190: // Validations have to be renewed, since they are only called
2191: // from readObject
2192: validations = null;
2193: }
2194: }
2195: return result;
2196: }
2197:
2198: /**
2199: * Method to be overriden by subclasses to read the next object from the
2200: * receiver's underlying stream.
2201: *
2202: * @return the new object read.
2203: *
2204: * @throws IOException
2205: * If an IO exception happened when reading the object
2206: * @throws ClassNotFoundException
2207: * If the class of one of the objects in the object graph could
2208: * not be found
2209: * @throws OptionalDataException
2210: * If primitive data types were found instead of an object.
2211: *
2212: * @see ObjectOutputStream#writeObjectOverride
2213: */
2214: protected Object readObjectOverride() throws OptionalDataException,
2215: ClassNotFoundException, IOException {
2216: if (input == null) {
2217: return null;
2218: }
2219: // Subclasses must override.
2220: throw new IOException();
2221: }
2222:
2223: /**
2224: * Reads and returns primitive data of type short from the receiver
2225: *
2226: * @return a short saved as primitive data using
2227: * <code>ObjectOutputStream.writeShort()</code>
2228: *
2229: * @throws IOException
2230: * If an IO exception happened when reading the primitive data.
2231: */
2232: public short readShort() throws IOException {
2233: return primitiveTypes.readShort();
2234: }
2235:
2236: /**
2237: * Reads and validates the ObjectInputStream header from the receiver
2238: *
2239: * @throws IOException
2240: * If an IO exception happened when reading the stream header.
2241: * @throws StreamCorruptedException
2242: * If the underlying stream does not contain serialized objects
2243: * that can be read.
2244: */
2245: protected void readStreamHeader() throws IOException,
2246: StreamCorruptedException {
2247: if (input.readShort() == STREAM_MAGIC
2248: && input.readShort() == STREAM_VERSION) {
2249: return;
2250: }
2251: throw new StreamCorruptedException();
2252: }
2253:
2254: /**
2255: * Reads and returns primitive data of type byte (unsigned) from the
2256: * receiver
2257: *
2258: * @return a byte saved as primitive data using
2259: * <code>ObjectOutputStream.writeUnsignedByte()</code>
2260: *
2261: * @throws IOException
2262: * If an IO exception happened when reading the primitive data.
2263: */
2264: public int readUnsignedByte() throws IOException {
2265: return primitiveTypes.readUnsignedByte();
2266: }
2267:
2268: /**
2269: * Reads and returns primitive data of type short (unsigned) from the
2270: * receiver
2271: *
2272: * @return a short saved as primitive data using
2273: * <code>ObjectOutputStream.writeUnsignedShort()</code>
2274: *
2275: * @throws IOException
2276: * If an IO exception happened when reading the primitive data.
2277: */
2278: public int readUnsignedShort() throws IOException {
2279: return primitiveTypes.readUnsignedShort();
2280: }
2281:
2282: /**
2283: * Reads and returns primitive data of type String read in UTF format from
2284: * the receiver
2285: *
2286: * @return a String saved as primitive data using
2287: * <code>ObjectOutputStream.writeUTF()</code>
2288: *
2289: * @throws IOException
2290: * If an IO exception happened when reading the primitive data.
2291: */
2292: public String readUTF() throws IOException {
2293: return primitiveTypes.readUTF();
2294: }
2295:
2296: /**
2297: * Return the object previously read tagged with handle <code>handle</code>.
2298: *
2299: * @param handle
2300: * The handle that this object was assigned when it was read.
2301: * @return the object previously read.
2302: *
2303: * @throws InvalidObjectException
2304: * If there is no previously read object with this handle
2305: */
2306: private Object registeredObjectRead(Integer handle)
2307: throws InvalidObjectException {
2308: Object res = objectsRead.get(handle);
2309:
2310: if (res == UNSHARED_OBJ) {
2311: throw new InvalidObjectException(Msg.getString("KA010")); //$NON-NLS-1$
2312: }
2313:
2314: return res;
2315: }
2316:
2317: /**
2318: * Assume object <code>obj</code> has been read, and assign a handle to
2319: * it, <code>handle</code>.
2320: *
2321: * @param obj
2322: * Non-null object being loaded.
2323: * @param handle
2324: * An Integer, the handle to this object
2325: * @param unshared
2326: * Boolean, indicates that caller is reading in unshared mode
2327: *
2328: * @see #nextHandle
2329: */
2330: private void registerObjectRead(Object obj, Integer handle,
2331: boolean unshared) {
2332: objectsRead.put(handle, unshared ? UNSHARED_OBJ : obj);
2333: }
2334:
2335: /**
2336: * Register object validator <code>object</code> to be executed to perform
2337: * validation of objects loaded from the receiver. Validations will be run
2338: * in order of decreasing priority, defined by <code>priority</code>.
2339: *
2340: * @param object
2341: * An ObjectInputValidation to validate objects loaded.
2342: * @param priority
2343: * validator priority
2344: *
2345: * @throws NotActiveException
2346: * If this method is not called from <code>readObject()</code>
2347: * @throws InvalidObjectException
2348: * If <code>object</code> is null.
2349: */
2350: public synchronized void registerValidation(
2351: ObjectInputValidation object, int priority)
2352: throws NotActiveException, InvalidObjectException {
2353: // Validation can only be registered when inside readObject calls
2354: Object instanceBeingRead = this .currentObject;
2355:
2356: // We can't be called from just anywhere. There are rules.
2357: if (instanceBeingRead == null && nestedLevels == 0) {
2358: throw new NotActiveException();
2359: }
2360: if (object == null) {
2361: throw new InvalidObjectException(Msg.getString("K00d9")); //$NON-NLS-1$
2362: }
2363: // From now on it is just insertion in a SortedCollection. Since
2364: // the Java class libraries don't provide that, we have to
2365: // implement it from scratch here.
2366: InputValidationDesc desc = new InputValidationDesc();
2367: desc.validator = object;
2368: desc.priority = priority;
2369: // No need for this, validateObject does not take a parameter
2370: // desc.toValidate = instanceBeingRead;
2371: if (validations == null) {
2372: validations = new InputValidationDesc[1];
2373: validations[0] = desc;
2374: } else {
2375: int i = 0;
2376: for (; i < validations.length; i++) {
2377: InputValidationDesc validation = validations[i];
2378: // Sorted, higher priority first.
2379: if (priority >= validation.priority) {
2380: break; // Found the index where to insert
2381: }
2382: }
2383: InputValidationDesc[] oldValidations = validations;
2384: int currentSize = oldValidations.length;
2385: validations = new InputValidationDesc[currentSize + 1];
2386: System.arraycopy(oldValidations, 0, validations, 0, i);
2387: System.arraycopy(oldValidations, i, validations, i + 1,
2388: currentSize - i);
2389: validations[i] = desc;
2390: }
2391: }
2392:
2393: /**
2394: * Reset the collection of objects already loaded by the receiver.
2395: */
2396: private void resetSeenObjects() {
2397: objectsRead = new Hashtable<Integer, Object>();
2398: currentHandle = baseWireHandle;
2399: primitiveData = emptyStream;
2400: }
2401:
2402: /**
2403: * Reset the receiver. The collection of objects already read by the
2404: * receiver is reset, and internal structures are also reset so that the
2405: * receiver knows it is in a fresh clean state.
2406: */
2407: private void resetState() {
2408: resetSeenObjects();
2409: hasPushbackTC = false;
2410: pushbackTC = 0;
2411: // nestedLevels = 0;
2412: }
2413:
2414: /**
2415: * Loads the Java class corresponding to the class descriptor
2416: * <code>osClass</code>(ObjectStreamClass) just read from the receiver.
2417: *
2418: * @param osClass
2419: * An ObjectStreamClass read from the receiver.
2420: * @return a Class corresponding to the descriptor loaded.
2421: *
2422: * @throws IOException
2423: * If any IO problem occurred when trying to load the class.
2424: * @throws ClassNotFoundException
2425: * If the corresponding class cannot be found.
2426: */
2427: protected Class<?> resolveClass(ObjectStreamClass osClass)
2428: throws IOException, ClassNotFoundException {
2429: String className = osClass.getName();
2430: // if it is primitive class, for example, long.class
2431: Class<?> cls = PRIMITIVE_CLASSES.get(className);
2432: if (null == cls) {
2433: // not primitive class
2434: // Use the first non-null ClassLoader on the stack. If null, use the
2435: // system class loader
2436: return Class.forName(className, true, callerClassLoader);
2437: }
2438: return cls;
2439: }
2440:
2441: /**
2442: * If <code>enableResolveObject()</code> was activated, computes the
2443: * replacement object for the original object <code>object</code> and
2444: * returns the replacement. Otherwise returns <code>object</code>.
2445: *
2446: * @param object
2447: * Original object for which a replacement may be defined
2448: * @return a possibly new, replacement object for <code>object</code>
2449: *
2450: * @throws IOException
2451: * If any IO problem occurred when trying to resolve the object.
2452: *
2453: * @see #enableResolveObject
2454: * @see ObjectOutputStream#enableReplaceObject
2455: * @see ObjectOutputStream#replaceObject
2456: */
2457: protected Object resolveObject(Object object) throws IOException {
2458: // By default no object replacement. Subclasses can override
2459: return object;
2460: }
2461:
2462: /**
2463: * Set a given declared field named <code>fieldName</code> of
2464: * <code>instance</code> to the new <code>byte</code> value
2465: * <code>value</code>.
2466: *
2467: * This method could be implemented non-natively on top of java.lang.reflect
2468: * implementations that support the <code>setAccessible</code> API, at the
2469: * expense of extra object creation (java.lang.reflect.Field). Otherwise
2470: * Serialization could not set private fields, except by the use of a native
2471: * method like this one.
2472: *
2473: * @param instance
2474: * Object whose field to set
2475: * @param declaringClass
2476: * <code>instance</code>'s declaring class
2477: * @param fieldName
2478: * Name of the field to set
2479: * @param value
2480: * New value for the field
2481: *
2482: * @throws NoSuchFieldError
2483: * If the field does not exist.
2484: */
2485: private static native void setField(Object instance,
2486: Class<?> declaringClass, String fieldName, byte value)
2487: throws NoSuchFieldError;
2488:
2489: /**
2490: * Set a given declared field named <code>fieldName</code> of
2491: * <code>instance</code> to the new <code>char</code> value
2492: * <code>value</code>.
2493: *
2494: * This method could be implemented non-natively on top of java.lang.reflect
2495: * implementations that support the <code>setAccessible</code> API, at the
2496: * expense of extra object creation (java.lang.reflect.Field). Otherwise
2497: * Serialization could not set private fields, except by the use of a native
2498: * method like this one.
2499: *
2500: * @param instance
2501: * Object whose field to set
2502: * @param declaringClass
2503: * <code>instance</code>'s declaring class
2504: * @param fieldName
2505: * Name of the field to set
2506: * @param value
2507: * New value for the field
2508: *
2509: * @throws NoSuchFieldError
2510: * If the field does not exist.
2511: */
2512: private static native void setField(Object instance,
2513: Class<?> declaringClass, String fieldName, char value)
2514: throws NoSuchFieldError;
2515:
2516: /**
2517: * Set a given declared field named <code>fieldName</code> of
2518: * <code>instance</code> to the new <code>double</code> value
2519: * <code>value</code>.
2520: *
2521: * This method could be implemented non-natively on top of java.lang.reflect
2522: * implementations that support the <code>setAccessible</code> API, at the
2523: * expense of extra object creation (java.lang.reflect.Field). Otherwise
2524: * Serialization could not set private fields, except by the use of a native
2525: * method like this one.
2526: *
2527: * @param instance
2528: * Object whose field to set
2529: * @param declaringClass
2530: * <code>instance</code>'s declaring class
2531: * @param fieldName
2532: * Name of the field to set
2533: * @param value
2534: * New value for the field
2535: *
2536: * @throws NoSuchFieldError
2537: * If the field does not exist.
2538: */
2539: private static native void setField(Object instance,
2540: Class<?> declaringClass, String fieldName, double value)
2541: throws NoSuchFieldError;
2542:
2543: /**
2544: * Set a given declared field named <code>fieldName</code> of
2545: * <code>instance</code> to the new <code>float</code> value
2546: * <code>value</code>.
2547: *
2548: * This method could be implemented non-natively on top of java.lang.reflect
2549: * implementations that support the <code>setAccessible</code> API, at the
2550: * expense of extra object creation (java.lang.reflect.Field). Otherwise
2551: * Serialization could not set private fields, except by the use of a native
2552: * method like this one.
2553: *
2554: * @param instance
2555: * Object whose field to set
2556: * @param declaringClass
2557: * <code>instance</code>'s declaring class
2558: * @param fieldName
2559: * Name of the field to set
2560: * @param value
2561: * New value for the field
2562: *
2563: * @throws NoSuchFieldError
2564: * If the field does not exist.
2565: */
2566: private static native void setField(Object instance,
2567: Class<?> declaringClass, String fieldName, float value)
2568: throws NoSuchFieldError;
2569:
2570: /**
2571: * Set a given declared field named <code>fieldName</code> of
2572: * <code>instance</code> to the new <code>int</code> value
2573: * <code>value</code>.
2574: *
2575: * This method could be implemented non-natively on top of java.lang.reflect
2576: * implementations that support the <code>setAccessible</code> API, at the
2577: * expense of extra object creation (java.lang.reflect.Field). Otherwise
2578: * Serialization could not set private fields, except by the use of a native
2579: * method like this one.
2580: *
2581: * @param instance
2582: * Object whose field to set
2583: * @param declaringClass
2584: * <code>instance</code>'s declaring class
2585: * @param fieldName
2586: * Name of the field to set
2587: * @param value
2588: * New value for the field
2589: *
2590: * @throws NoSuchFieldError
2591: * If the field does not exist.
2592: */
2593: private static native void setField(Object instance,
2594: Class<?> declaringClass, String fieldName, int value)
2595: throws NoSuchFieldError;
2596:
2597: /**
2598: * Set a given declared field named <code>fieldName</code> of
2599: * <code>instance</code> to the new <code>long</code> value
2600: * <code>value</code>.
2601: *
2602: * This method could be implemented non-natively on top of java.lang.reflect
2603: * implementations that support the <code>setAccessible</code> API, at the
2604: * expense of extra object creation (java.lang.reflect.Field). Otherwise
2605: * Serialization could not set private fields, except by the use of a native
2606: * method like this one.
2607: *
2608: * @param instance
2609: * Object whose field to set
2610: * @param declaringClass
2611: * <code>instance</code>'s declaring class
2612: * @param fieldName
2613: * Name of the field to set
2614: * @param value
2615: * New value for the field
2616: *
2617: * @throws NoSuchFieldError
2618: * If the field does not exist.
2619: */
2620: private static native void setField(Object instance,
2621: Class<?> declaringClass, String fieldName, long value)
2622: throws NoSuchFieldError;
2623:
2624: /**
2625: * Set a given declared field named <code>fieldName</code> of
2626: * <code>instance</code> to the new value <code>value</code>.
2627: *
2628: * This method could be implemented non-natively on top of java.lang.reflect
2629: * implementations that support the <code>setAccessible</code> API, at the
2630: * expense of extra object creation (java.lang.reflect.Field). Otherwise
2631: * Serialization could not set private fields, except by the use of a native
2632: * method like this one.
2633: *
2634: * @param instance
2635: * Object whose field to set
2636: * @param declaringClass
2637: * Class which declares the field
2638: * @param fieldName
2639: * Name of the field to set
2640: * @param fieldTypeName
2641: * Name of the class defining the type of the field
2642: * @param value
2643: * New value for the field
2644: *
2645: * @throws NoSuchFieldError
2646: * If the field does not exist.
2647: */
2648: private static native void objSetField(Object instance,
2649: Class<?> declaringClass, String fieldName,
2650: String fieldTypeName, Object value) throws NoSuchFieldError;
2651:
2652: /**
2653: * Set a given declared field named <code>fieldName</code> of
2654: * <code>instance</code> to the new <code>short</code> value
2655: * <code>value</code>.
2656: *
2657: * This method could be implemented non-natively on top of java.lang.reflect
2658: * implementations that support the <code>setAccessible</code> API, at the
2659: * expense of extra object creation (java.lang.reflect.Field). Otherwise
2660: * Serialization could not set private fields, except by the use of a native
2661: * method like this one.
2662: *
2663: * @param instance
2664: * Object whose field to set
2665: * @param declaringClass
2666: * <code>instance</code>'s declaring class
2667: * @param fieldName
2668: * Name of the field to set
2669: * @param value
2670: * New value for the field
2671: *
2672: * @throws NoSuchFieldError
2673: * If the field does not exist.
2674: */
2675: private static native void setField(Object instance,
2676: Class<?> declaringClass, String fieldName, short value)
2677: throws NoSuchFieldError;
2678:
2679: /**
2680: * Set a given declared field named <code>fieldName</code> of
2681: * <code>instance</code> to the new <code>boolean</code> value
2682: * <code>value</code>.
2683: *
2684: * This method could be implemented non-natively on top of java.lang.reflect
2685: * implementations that support the <code>setAccessible</code> API, at the
2686: * expense of extra object creation (java.lang.reflect.Field). Otherwise
2687: * Serialization could not set private fields, except by the use of a native
2688: * method like this one.
2689: *
2690: * @param instance
2691: * Object whose field to set
2692: * @param declaringClass
2693: * <code>instance</code>'s declaring class
2694: * @param fieldName
2695: * Name of the field to set
2696: * @param value
2697: * New value for the field
2698: *
2699: * @throws NoSuchFieldError
2700: * If the field does not exist.
2701: */
2702: private static native void setField(Object instance,
2703: Class<?> declaringClass, String fieldName, boolean value)
2704: throws NoSuchFieldError;
2705:
2706: /**
2707: * Skips <code>length</code> bytes of primitive data from the receiver. It
2708: * should not be used to skip bytes at any arbitrary position; just when
2709: * reading primitive data types (ints, chars, etc).
2710: *
2711: *
2712: * @param length
2713: * How many bytes to skip
2714: * @return number of bytes skipped
2715: *
2716: * @throws IOException
2717: * If any IO problem occurred when trying to skip the bytes.
2718: */
2719: public int skipBytes(int length) throws IOException {
2720: // To be used with available. Ok to call if reading primitive buffer
2721: if (input == null) {
2722: throw new NullPointerException();
2723: }
2724:
2725: int offset = 0;
2726: while (offset < length) {
2727: checkReadPrimitiveTypes();
2728: long skipped = primitiveData.skip(length - offset);
2729: if (skipped == 0) {
2730: return offset;
2731: }
2732: offset += (int) skipped;
2733: }
2734: return length;
2735: }
2736:
2737: /**
2738: * Verify if the SUID & the base name for descriptor
2739: * <code>loadedStreamClass</code>matches
2740: * the SUID & the base name of the corresponding loaded class and
2741: * init private fields.
2742: *
2743: * @param loadedStreamClass
2744: * An ObjectStreamClass that was loaded from the stream.
2745: *
2746: * @throws InvalidClassException
2747: * If the SUID of the stream class does not match the VM class
2748: */
2749: private void verifyAndInit(ObjectStreamClass loadedStreamClass)
2750: throws InvalidClassException {
2751:
2752: Class<?> localClass = loadedStreamClass.forClass();
2753: ObjectStreamClass localStreamClass = ObjectStreamClass
2754: .lookupStreamClass(localClass);
2755:
2756: if (loadedStreamClass.getSerialVersionUID() != localStreamClass
2757: .getSerialVersionUID()) {
2758: throw new InvalidClassException(
2759: loadedStreamClass.getName(), Msg.getString(
2760: "K00da", loadedStreamClass, //$NON-NLS-1$
2761: localStreamClass));
2762: }
2763:
2764: String loadedClassBaseName = getBaseName(loadedStreamClass
2765: .getName());
2766: String localClassBaseName = getBaseName(localStreamClass
2767: .getName());
2768:
2769: if (!loadedClassBaseName.equals(localClassBaseName)) {
2770: throw new InvalidClassException(
2771: loadedStreamClass.getName(), Msg.getString(
2772: "KA015", loadedClassBaseName, //$NON-NLS-1$
2773: localClassBaseName));
2774: }
2775:
2776: loadedStreamClass.initPrivateFields(localStreamClass);
2777: }
2778:
2779: private static String getBaseName(String fullName) {
2780: int k = fullName.lastIndexOf("."); //$NON-NLS-1$
2781:
2782: if (k == -1 || k == (fullName.length() - 1)) {
2783: return fullName;
2784: }
2785: return fullName.substring(k + 1);
2786: }
2787:
2788: // Avoid recursive defining.
2789: private static void checkedSetSuperClassDesc(
2790: ObjectStreamClass desc, ObjectStreamClass super Desc)
2791: throws StreamCorruptedException {
2792: if (desc.equals(super Desc)) {
2793: throw new StreamCorruptedException();
2794: }
2795: desc.setSuperclass(superDesc);
2796: }
2797: }
|