jaroslav@601: /* jaroslav@601: * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved. jaroslav@601: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. jaroslav@601: * jaroslav@601: * This code is free software; you can redistribute it and/or modify it jaroslav@601: * under the terms of the GNU General Public License version 2 only, as jaroslav@601: * published by the Free Software Foundation. Oracle designates this jaroslav@601: * particular file as subject to the "Classpath" exception as provided jaroslav@601: * by Oracle in the LICENSE file that accompanied this code. jaroslav@601: * jaroslav@601: * This code is distributed in the hope that it will be useful, but WITHOUT jaroslav@601: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or jaroslav@601: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License jaroslav@601: * version 2 for more details (a copy is included in the LICENSE file that jaroslav@601: * accompanied this code). jaroslav@601: * jaroslav@601: * You should have received a copy of the GNU General Public License version jaroslav@601: * 2 along with this work; if not, write to the Free Software Foundation, jaroslav@601: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. jaroslav@601: * jaroslav@601: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA jaroslav@601: * or visit www.oracle.com if you need additional information or have any jaroslav@601: * questions. jaroslav@601: */ jaroslav@601: jaroslav@601: package java.io; jaroslav@601: jaroslav@601: import java.lang.reflect.Field; jaroslav@601: jaroslav@601: /** jaroslav@601: * A description of a Serializable field from a Serializable class. An array jaroslav@601: * of ObjectStreamFields is used to declare the Serializable fields of a class. jaroslav@601: * jaroslav@601: * @author Mike Warres jaroslav@601: * @author Roger Riggs jaroslav@601: * @see ObjectStreamClass jaroslav@601: * @since 1.2 jaroslav@601: */ jaroslav@601: public class ObjectStreamField jaroslav@601: implements Comparable jaroslav@601: { jaroslav@601: jaroslav@601: /** field name */ jaroslav@601: private final String name; jaroslav@601: /** canonical JVM signature of field type */ jaroslav@601: private final String signature; jaroslav@601: /** field type (Object.class if unknown non-primitive type) */ jaroslav@601: private final Class type; jaroslav@601: /** whether or not to (de)serialize field values as unshared */ jaroslav@601: private final boolean unshared; jaroslav@601: /** corresponding reflective field object, if any */ jaroslav@601: private final Field field; jaroslav@601: /** offset of field value in enclosing field group */ jaroslav@601: private int offset = 0; jaroslav@601: jaroslav@601: /** jaroslav@601: * Create a Serializable field with the specified type. This field should jaroslav@601: * be documented with a serialField tag. jaroslav@601: * jaroslav@601: * @param name the name of the serializable field jaroslav@601: * @param type the Class object of the serializable field jaroslav@601: */ jaroslav@601: public ObjectStreamField(String name, Class type) { jaroslav@601: this(name, type, false); jaroslav@601: } jaroslav@601: jaroslav@601: /** jaroslav@601: * Creates an ObjectStreamField representing a serializable field with the jaroslav@601: * given name and type. If unshared is false, values of the represented jaroslav@601: * field are serialized and deserialized in the default manner--if the jaroslav@601: * field is non-primitive, object values are serialized and deserialized as jaroslav@601: * if they had been written and read by calls to writeObject and jaroslav@601: * readObject. If unshared is true, values of the represented field are jaroslav@601: * serialized and deserialized as if they had been written and read by jaroslav@601: * calls to writeUnshared and readUnshared. jaroslav@601: * jaroslav@601: * @param name field name jaroslav@601: * @param type field type jaroslav@601: * @param unshared if false, write/read field values in the same manner jaroslav@601: * as writeObject/readObject; if true, write/read in the same jaroslav@601: * manner as writeUnshared/readUnshared jaroslav@601: * @since 1.4 jaroslav@601: */ jaroslav@601: public ObjectStreamField(String name, Class type, boolean unshared) { jaroslav@601: if (name == null) { jaroslav@601: throw new NullPointerException(); jaroslav@601: } jaroslav@601: this.name = name; jaroslav@601: this.type = type; jaroslav@601: this.unshared = unshared; jaroslav@601: signature = getClassSignature(type).intern(); jaroslav@601: field = null; jaroslav@601: } jaroslav@601: jaroslav@601: /** jaroslav@601: * Creates an ObjectStreamField representing a field with the given name, jaroslav@601: * signature and unshared setting. jaroslav@601: */ jaroslav@601: ObjectStreamField(String name, String signature, boolean unshared) { jaroslav@601: if (name == null) { jaroslav@601: throw new NullPointerException(); jaroslav@601: } jaroslav@601: this.name = name; jaroslav@601: this.signature = signature.intern(); jaroslav@601: this.unshared = unshared; jaroslav@601: field = null; jaroslav@601: jaroslav@601: switch (signature.charAt(0)) { jaroslav@601: case 'Z': type = Boolean.TYPE; break; jaroslav@601: case 'B': type = Byte.TYPE; break; jaroslav@601: case 'C': type = Character.TYPE; break; jaroslav@601: case 'S': type = Short.TYPE; break; jaroslav@601: case 'I': type = Integer.TYPE; break; jaroslav@601: case 'J': type = Long.TYPE; break; jaroslav@601: case 'F': type = Float.TYPE; break; jaroslav@601: case 'D': type = Double.TYPE; break; jaroslav@601: case 'L': jaroslav@601: case '[': type = Object.class; break; jaroslav@601: default: throw new IllegalArgumentException("illegal signature"); jaroslav@601: } jaroslav@601: } jaroslav@601: jaroslav@601: /** jaroslav@601: * Creates an ObjectStreamField representing the given field with the jaroslav@601: * specified unshared setting. For compatibility with the behavior of jaroslav@601: * earlier serialization implementations, a "showType" parameter is jaroslav@601: * necessary to govern whether or not a getType() call on this jaroslav@601: * ObjectStreamField (if non-primitive) will return Object.class (as jaroslav@601: * opposed to a more specific reference type). jaroslav@601: */ jaroslav@601: ObjectStreamField(Field field, boolean unshared, boolean showType) { jaroslav@601: this.field = field; jaroslav@601: this.unshared = unshared; jaroslav@601: name = field.getName(); jaroslav@601: Class ftype = field.getType(); jaroslav@601: type = (showType || ftype.isPrimitive()) ? ftype : Object.class; jaroslav@601: signature = getClassSignature(ftype).intern(); jaroslav@601: } jaroslav@601: jaroslav@601: /** jaroslav@601: * Get the name of this field. jaroslav@601: * jaroslav@601: * @return a String representing the name of the serializable jaroslav@601: * field jaroslav@601: */ jaroslav@601: public String getName() { jaroslav@601: return name; jaroslav@601: } jaroslav@601: jaroslav@601: /** jaroslav@601: * Get the type of the field. If the type is non-primitive and this jaroslav@601: * ObjectStreamField was obtained from a deserialized {@link jaroslav@601: * ObjectStreamClass} instance, then Object.class is returned. jaroslav@601: * Otherwise, the Class object for the type of the field is jaroslav@601: * returned. jaroslav@601: * jaroslav@601: * @return a Class object representing the type of the jaroslav@601: * serializable field jaroslav@601: */ jaroslav@601: public Class getType() { jaroslav@601: return type; jaroslav@601: } jaroslav@601: jaroslav@601: /** jaroslav@601: * Returns character encoding of field type. The encoding is as follows: jaroslav@601: *
jaroslav@601:      * B            byte
jaroslav@601:      * C            char
jaroslav@601:      * D            double
jaroslav@601:      * F            float
jaroslav@601:      * I            int
jaroslav@601:      * J            long
jaroslav@601:      * L            class or interface
jaroslav@601:      * S            short
jaroslav@601:      * Z            boolean
jaroslav@601:      * [            array
jaroslav@601:      * 
jaroslav@601: * jaroslav@601: * @return the typecode of the serializable field jaroslav@601: */ jaroslav@601: // REMIND: deprecate? jaroslav@601: public char getTypeCode() { jaroslav@601: return signature.charAt(0); jaroslav@601: } jaroslav@601: jaroslav@601: /** jaroslav@601: * Return the JVM type signature. jaroslav@601: * jaroslav@601: * @return null if this field has a primitive type. jaroslav@601: */ jaroslav@601: // REMIND: deprecate? jaroslav@601: public String getTypeString() { jaroslav@601: return isPrimitive() ? null : signature; jaroslav@601: } jaroslav@601: jaroslav@601: /** jaroslav@601: * Offset of field within instance data. jaroslav@601: * jaroslav@601: * @return the offset of this field jaroslav@601: * @see #setOffset jaroslav@601: */ jaroslav@601: // REMIND: deprecate? jaroslav@601: public int getOffset() { jaroslav@601: return offset; jaroslav@601: } jaroslav@601: jaroslav@601: /** jaroslav@601: * Offset within instance data. jaroslav@601: * jaroslav@601: * @param offset the offset of the field jaroslav@601: * @see #getOffset jaroslav@601: */ jaroslav@601: // REMIND: deprecate? jaroslav@601: protected void setOffset(int offset) { jaroslav@601: this.offset = offset; jaroslav@601: } jaroslav@601: jaroslav@601: /** jaroslav@601: * Return true if this field has a primitive type. jaroslav@601: * jaroslav@601: * @return true if and only if this field corresponds to a primitive type jaroslav@601: */ jaroslav@601: // REMIND: deprecate? jaroslav@601: public boolean isPrimitive() { jaroslav@601: char tcode = signature.charAt(0); jaroslav@601: return ((tcode != 'L') && (tcode != '[')); jaroslav@601: } jaroslav@601: jaroslav@601: /** jaroslav@601: * Returns boolean value indicating whether or not the serializable field jaroslav@601: * represented by this ObjectStreamField instance is unshared. jaroslav@601: * jaroslav@601: * @since 1.4 jaroslav@601: */ jaroslav@601: public boolean isUnshared() { jaroslav@601: return unshared; jaroslav@601: } jaroslav@601: jaroslav@601: /** jaroslav@601: * Compare this field with another ObjectStreamField. Return jaroslav@601: * -1 if this is smaller, 0 if equal, 1 if greater. Types that are jaroslav@601: * primitives are "smaller" than object types. If equal, the field names jaroslav@601: * are compared. jaroslav@601: */ jaroslav@601: // REMIND: deprecate? jaroslav@601: public int compareTo(Object obj) { jaroslav@601: ObjectStreamField other = (ObjectStreamField) obj; jaroslav@601: boolean isPrim = isPrimitive(); jaroslav@601: if (isPrim != other.isPrimitive()) { jaroslav@601: return isPrim ? -1 : 1; jaroslav@601: } jaroslav@601: return name.compareTo(other.name); jaroslav@601: } jaroslav@601: jaroslav@601: /** jaroslav@601: * Return a string that describes this field. jaroslav@601: */ jaroslav@601: public String toString() { jaroslav@601: return signature + ' ' + name; jaroslav@601: } jaroslav@601: jaroslav@601: /** jaroslav@601: * Returns field represented by this ObjectStreamField, or null if jaroslav@601: * ObjectStreamField is not associated with an actual field. jaroslav@601: */ jaroslav@601: Field getField() { jaroslav@601: return field; jaroslav@601: } jaroslav@601: jaroslav@601: /** jaroslav@601: * Returns JVM type signature of field (similar to getTypeString, except jaroslav@601: * that signature strings are returned for primitive fields as well). jaroslav@601: */ jaroslav@601: String getSignature() { jaroslav@601: return signature; jaroslav@601: } jaroslav@601: jaroslav@601: /** jaroslav@601: * Returns JVM type signature for given class. jaroslav@601: */ jaroslav@601: private static String getClassSignature(Class cl) { jaroslav@601: StringBuilder sbuf = new StringBuilder(); jaroslav@601: while (cl.isArray()) { jaroslav@601: sbuf.append('['); jaroslav@601: cl = cl.getComponentType(); jaroslav@601: } jaroslav@601: if (cl.isPrimitive()) { jaroslav@601: if (cl == Integer.TYPE) { jaroslav@601: sbuf.append('I'); jaroslav@601: } else if (cl == Byte.TYPE) { jaroslav@601: sbuf.append('B'); jaroslav@601: } else if (cl == Long.TYPE) { jaroslav@601: sbuf.append('J'); jaroslav@601: } else if (cl == Float.TYPE) { jaroslav@601: sbuf.append('F'); jaroslav@601: } else if (cl == Double.TYPE) { jaroslav@601: sbuf.append('D'); jaroslav@601: } else if (cl == Short.TYPE) { jaroslav@601: sbuf.append('S'); jaroslav@601: } else if (cl == Character.TYPE) { jaroslav@601: sbuf.append('C'); jaroslav@601: } else if (cl == Boolean.TYPE) { jaroslav@601: sbuf.append('Z'); jaroslav@601: } else if (cl == Void.TYPE) { jaroslav@601: sbuf.append('V'); jaroslav@601: } else { jaroslav@601: throw new InternalError(); jaroslav@601: } jaroslav@601: } else { jaroslav@601: sbuf.append('L' + cl.getName().replace('.', '/') + ';'); jaroslav@601: } jaroslav@601: return sbuf.toString(); jaroslav@601: } jaroslav@601: }