1 /* 2 * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.io; 27 28 import java.lang.reflect.Field; 29 import sun.reflect.CallerSensitive; 30 import sun.reflect.Reflection; 31 import sun.reflect.misc.ReflectUtil; 32 import dalvik.system.VMStack; 33 34 /** 35 * A description of a Serializable field from a Serializable class. An array 36 * of ObjectStreamFields is used to declare the Serializable fields of a class. 37 * 38 * @author Mike Warres 39 * @author Roger Riggs 40 * @see ObjectStreamClass 41 * @since 1.2 42 */ 43 public class ObjectStreamField 44 implements Comparable<Object> 45 { 46 47 /** field name */ 48 private final String name; 49 /** canonical JVM signature of field type */ 50 private final String signature; 51 /** field type (Object.class if unknown non-primitive type) */ 52 private final Class<?> type; 53 /** whether or not to (de)serialize field values as unshared */ 54 private final boolean unshared; 55 /** corresponding reflective field object, if any */ 56 private final Field field; 57 /** offset of field value in enclosing field group */ 58 private int offset = 0; 59 60 /** 61 * Create a Serializable field with the specified type. This field should 62 * be documented with a <code>serialField</code> tag. 63 * 64 * @param name the name of the serializable field 65 * @param type the <code>Class</code> object of the serializable field 66 */ ObjectStreamField(String name, Class<?> type)67 public ObjectStreamField(String name, Class<?> type) { 68 this(name, type, false); 69 } 70 71 /** 72 * Creates an ObjectStreamField representing a serializable field with the 73 * given name and type. If unshared is false, values of the represented 74 * field are serialized and deserialized in the default manner--if the 75 * field is non-primitive, object values are serialized and deserialized as 76 * if they had been written and read by calls to writeObject and 77 * readObject. If unshared is true, values of the represented field are 78 * serialized and deserialized as if they had been written and read by 79 * calls to writeUnshared and readUnshared. 80 * 81 * @param name field name 82 * @param type field type 83 * @param unshared if false, write/read field values in the same manner 84 * as writeObject/readObject; if true, write/read in the same 85 * manner as writeUnshared/readUnshared 86 * @since 1.4 87 */ ObjectStreamField(String name, Class<?> type, boolean unshared)88 public ObjectStreamField(String name, Class<?> type, boolean unshared) { 89 if (name == null) { 90 throw new NullPointerException(); 91 } 92 this.name = name; 93 this.type = type; 94 this.unshared = unshared; 95 signature = getClassSignature(type).intern(); 96 field = null; 97 } 98 99 /** 100 * Creates an ObjectStreamField representing a field with the given name, 101 * signature and unshared setting. 102 */ ObjectStreamField(String name, String signature, boolean unshared)103 ObjectStreamField(String name, String signature, boolean unshared) { 104 if (name == null) { 105 throw new NullPointerException(); 106 } 107 this.name = name; 108 this.signature = signature.intern(); 109 this.unshared = unshared; 110 field = null; 111 112 switch (signature.charAt(0)) { 113 case 'Z': type = Boolean.TYPE; break; 114 case 'B': type = Byte.TYPE; break; 115 case 'C': type = Character.TYPE; break; 116 case 'S': type = Short.TYPE; break; 117 case 'I': type = Integer.TYPE; break; 118 case 'J': type = Long.TYPE; break; 119 case 'F': type = Float.TYPE; break; 120 case 'D': type = Double.TYPE; break; 121 case 'L': 122 case '[': type = Object.class; break; 123 default: throw new IllegalArgumentException("illegal signature"); 124 } 125 } 126 127 /** 128 * Creates an ObjectStreamField representing the given field with the 129 * specified unshared setting. For compatibility with the behavior of 130 * earlier serialization implementations, a "showType" parameter is 131 * necessary to govern whether or not a getType() call on this 132 * ObjectStreamField (if non-primitive) will return Object.class (as 133 * opposed to a more specific reference type). 134 */ ObjectStreamField(Field field, boolean unshared, boolean showType)135 ObjectStreamField(Field field, boolean unshared, boolean showType) { 136 this.field = field; 137 this.unshared = unshared; 138 name = field.getName(); 139 Class<?> ftype = field.getType(); 140 type = (showType || ftype.isPrimitive()) ? ftype : Object.class; 141 signature = getClassSignature(ftype).intern(); 142 } 143 144 /** 145 * Get the name of this field. 146 * 147 * @return a <code>String</code> representing the name of the serializable 148 * field 149 */ getName()150 public String getName() { 151 return name; 152 } 153 154 /** 155 * Get the type of the field. If the type is non-primitive and this 156 * <code>ObjectStreamField</code> was obtained from a deserialized {@link 157 * ObjectStreamClass} instance, then <code>Object.class</code> is returned. 158 * Otherwise, the <code>Class</code> object for the type of the field is 159 * returned. 160 * 161 * @return a <code>Class</code> object representing the type of the 162 * serializable field 163 */ 164 @CallerSensitive getType()165 public Class<?> getType() { 166 return type; 167 } 168 169 /** 170 * Returns character encoding of field type. The encoding is as follows: 171 * <blockquote><pre> 172 * B byte 173 * C char 174 * D double 175 * F float 176 * I int 177 * J long 178 * L class or interface 179 * S short 180 * Z boolean 181 * [ array 182 * </pre></blockquote> 183 * 184 * @return the typecode of the serializable field 185 */ 186 // REMIND: deprecate? getTypeCode()187 public char getTypeCode() { 188 return signature.charAt(0); 189 } 190 191 /** 192 * Return the JVM type signature. 193 * 194 * @return null if this field has a primitive type. 195 */ 196 // REMIND: deprecate? getTypeString()197 public String getTypeString() { 198 return isPrimitive() ? null : signature; 199 } 200 201 /** 202 * Offset of field within instance data. 203 * 204 * @return the offset of this field 205 * @see #setOffset 206 */ 207 // REMIND: deprecate? getOffset()208 public int getOffset() { 209 return offset; 210 } 211 212 /** 213 * Offset within instance data. 214 * 215 * @param offset the offset of the field 216 * @see #getOffset 217 */ 218 // REMIND: deprecate? setOffset(int offset)219 protected void setOffset(int offset) { 220 this.offset = offset; 221 } 222 223 /** 224 * Return true if this field has a primitive type. 225 * 226 * @return true if and only if this field corresponds to a primitive type 227 */ 228 // REMIND: deprecate? isPrimitive()229 public boolean isPrimitive() { 230 char tcode = signature.charAt(0); 231 return ((tcode != 'L') && (tcode != '[')); 232 } 233 234 /** 235 * Returns boolean value indicating whether or not the serializable field 236 * represented by this ObjectStreamField instance is unshared. 237 * 238 * @since 1.4 239 */ isUnshared()240 public boolean isUnshared() { 241 return unshared; 242 } 243 244 /** 245 * Compare this field with another <code>ObjectStreamField</code>. Return 246 * -1 if this is smaller, 0 if equal, 1 if greater. Types that are 247 * primitives are "smaller" than object types. If equal, the field names 248 * are compared. 249 */ 250 // REMIND: deprecate? compareTo(Object obj)251 public int compareTo(Object obj) { 252 ObjectStreamField other = (ObjectStreamField) obj; 253 boolean isPrim = isPrimitive(); 254 if (isPrim != other.isPrimitive()) { 255 return isPrim ? -1 : 1; 256 } 257 return name.compareTo(other.name); 258 } 259 260 /** 261 * Return a string that describes this field. 262 */ toString()263 public String toString() { 264 return signature + ' ' + name; 265 } 266 267 /** 268 * Returns field represented by this ObjectStreamField, or null if 269 * ObjectStreamField is not associated with an actual field. 270 */ getField()271 Field getField() { 272 return field; 273 } 274 275 /** 276 * Returns JVM type signature of field (similar to getTypeString, except 277 * that signature strings are returned for primitive fields as well). 278 */ getSignature()279 String getSignature() { 280 return signature; 281 } 282 283 /** 284 * Returns JVM type signature for given class. 285 */ getClassSignature(Class<?> cl)286 private static String getClassSignature(Class<?> cl) { 287 StringBuilder sbuf = new StringBuilder(); 288 while (cl.isArray()) { 289 sbuf.append('['); 290 cl = cl.getComponentType(); 291 } 292 if (cl.isPrimitive()) { 293 if (cl == Integer.TYPE) { 294 sbuf.append('I'); 295 } else if (cl == Byte.TYPE) { 296 sbuf.append('B'); 297 } else if (cl == Long.TYPE) { 298 sbuf.append('J'); 299 } else if (cl == Float.TYPE) { 300 sbuf.append('F'); 301 } else if (cl == Double.TYPE) { 302 sbuf.append('D'); 303 } else if (cl == Short.TYPE) { 304 sbuf.append('S'); 305 } else if (cl == Character.TYPE) { 306 sbuf.append('C'); 307 } else if (cl == Boolean.TYPE) { 308 sbuf.append('Z'); 309 } else if (cl == Void.TYPE) { 310 sbuf.append('V'); 311 } else { 312 throw new InternalError(); 313 } 314 } else { 315 sbuf.append('L' + cl.getName().replace('.', '/') + ';'); 316 } 317 return sbuf.toString(); 318 } 319 } 320