1 /* 2 * Copyright (c) 1996, 2013, 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 33 /** 34 * A description of a Serializable field from a Serializable class. An array 35 * of ObjectStreamFields is used to declare the Serializable fields of a class. 36 * 37 * @author Mike Warres 38 * @author Roger Riggs 39 * @see ObjectStreamClass 40 * @since 1.2 41 */ 42 public class ObjectStreamField 43 implements Comparable<Object> 44 { 45 46 /** field name */ 47 private final String name; 48 /** canonical JVM signature of field type */ 49 private final String signature; 50 /** field type (Object.class if unknown non-primitive type) */ 51 private final Class<?> type; 52 /** whether or not to (de)serialize field values as unshared */ 53 private final boolean unshared; 54 /** corresponding reflective field object, if any */ 55 private final Field field; 56 /** offset of field value in enclosing field group */ 57 private int offset = 0; 58 59 /** 60 * Create a Serializable field with the specified type. This field should 61 * be documented with a <code>serialField</code> tag. 62 * 63 * @param name the name of the serializable field 64 * @param type the <code>Class</code> object of the serializable field 65 */ ObjectStreamField(String name, Class<?> type)66 public ObjectStreamField(String name, Class<?> type) { 67 this(name, type, false); 68 } 69 70 /** 71 * Creates an ObjectStreamField representing a serializable field with the 72 * given name and type. If unshared is false, values of the represented 73 * field are serialized and deserialized in the default manner--if the 74 * field is non-primitive, object values are serialized and deserialized as 75 * if they had been written and read by calls to writeObject and 76 * readObject. If unshared is true, values of the represented field are 77 * serialized and deserialized as if they had been written and read by 78 * calls to writeUnshared and readUnshared. 79 * 80 * @param name field name 81 * @param type field type 82 * @param unshared if false, write/read field values in the same manner 83 * as writeObject/readObject; if true, write/read in the same 84 * manner as writeUnshared/readUnshared 85 * @since 1.4 86 */ ObjectStreamField(String name, Class<?> type, boolean unshared)87 public ObjectStreamField(String name, Class<?> type, boolean unshared) { 88 if (name == null) { 89 throw new NullPointerException(); 90 } 91 this.name = name; 92 this.type = type; 93 this.unshared = unshared; 94 signature = getClassSignature(type).intern(); 95 field = null; 96 } 97 98 /** 99 * Creates an ObjectStreamField representing a field with the given name, 100 * signature and unshared setting. 101 */ ObjectStreamField(String name, String signature, boolean unshared)102 ObjectStreamField(String name, String signature, boolean unshared) { 103 if (name == null) { 104 throw new NullPointerException(); 105 } 106 this.name = name; 107 this.signature = signature.intern(); 108 this.unshared = unshared; 109 field = null; 110 111 switch (signature.charAt(0)) { 112 case 'Z': type = Boolean.TYPE; break; 113 case 'B': type = Byte.TYPE; break; 114 case 'C': type = Character.TYPE; break; 115 case 'S': type = Short.TYPE; break; 116 case 'I': type = Integer.TYPE; break; 117 case 'J': type = Long.TYPE; break; 118 case 'F': type = Float.TYPE; break; 119 case 'D': type = Double.TYPE; break; 120 case 'L': 121 case '[': type = Object.class; break; 122 default: throw new IllegalArgumentException("illegal signature"); 123 } 124 } 125 126 /** 127 * Creates an ObjectStreamField representing the given field with the 128 * specified unshared setting. For compatibility with the behavior of 129 * earlier serialization implementations, a "showType" parameter is 130 * necessary to govern whether or not a getType() call on this 131 * ObjectStreamField (if non-primitive) will return Object.class (as 132 * opposed to a more specific reference type). 133 */ ObjectStreamField(Field field, boolean unshared, boolean showType)134 ObjectStreamField(Field field, boolean unshared, boolean showType) { 135 this.field = field; 136 this.unshared = unshared; 137 name = field.getName(); 138 Class<?> ftype = field.getType(); 139 type = (showType || ftype.isPrimitive()) ? ftype : Object.class; 140 signature = getClassSignature(ftype).intern(); 141 } 142 143 /** 144 * Get the name of this field. 145 * 146 * @return a <code>String</code> representing the name of the serializable 147 * field 148 */ getName()149 public String getName() { 150 return name; 151 } 152 153 /** 154 * Get the type of the field. If the type is non-primitive and this 155 * <code>ObjectStreamField</code> was obtained from a deserialized {@link 156 * ObjectStreamClass} instance, then <code>Object.class</code> is returned. 157 * Otherwise, the <code>Class</code> object for the type of the field is 158 * returned. 159 * 160 * @return a <code>Class</code> object representing the type of the 161 * serializable field 162 */ 163 @CallerSensitive getType()164 public Class<?> getType() { 165 // BEGIN Android-removed: Security manager is always null on Android. 166 /* 167 if (System.getSecurityManager() != null) { 168 Class<?> caller = Reflection.getCallerClass(); 169 if (ReflectUtil.needsPackageAccessCheck(caller.getClassLoader(), type.getClassLoader())) { 170 ReflectUtil.checkPackageAccess(type); 171 } 172 } 173 */ 174 // END Android-removed: Security manager is always null on Android. 175 return type; 176 } 177 178 /** 179 * Returns character encoding of field type. The encoding is as follows: 180 * <blockquote><pre> 181 * B byte 182 * C char 183 * D double 184 * F float 185 * I int 186 * J long 187 * L class or interface 188 * S short 189 * Z boolean 190 * [ array 191 * </pre></blockquote> 192 * 193 * @return the typecode of the serializable field 194 */ 195 // REMIND: deprecate? getTypeCode()196 public char getTypeCode() { 197 return signature.charAt(0); 198 } 199 200 /** 201 * Return the JVM type signature. 202 * 203 * @return null if this field has a primitive type. 204 */ 205 // REMIND: deprecate? getTypeString()206 public String getTypeString() { 207 return isPrimitive() ? null : signature; 208 } 209 210 /** 211 * Offset of field within instance data. 212 * 213 * @return the offset of this field 214 * @see #setOffset 215 */ 216 // REMIND: deprecate? getOffset()217 public int getOffset() { 218 return offset; 219 } 220 221 /** 222 * Offset within instance data. 223 * 224 * @param offset the offset of the field 225 * @see #getOffset 226 */ 227 // REMIND: deprecate? setOffset(int offset)228 protected void setOffset(int offset) { 229 this.offset = offset; 230 } 231 232 /** 233 * Return true if this field has a primitive type. 234 * 235 * @return true if and only if this field corresponds to a primitive type 236 */ 237 // REMIND: deprecate? isPrimitive()238 public boolean isPrimitive() { 239 char tcode = signature.charAt(0); 240 return ((tcode != 'L') && (tcode != '[')); 241 } 242 243 /** 244 * Returns boolean value indicating whether or not the serializable field 245 * represented by this ObjectStreamField instance is unshared. 246 * 247 * @return {@code true} if this field is unshared 248 * 249 * @since 1.4 250 */ isUnshared()251 public boolean isUnshared() { 252 return unshared; 253 } 254 255 /** 256 * Compare this field with another <code>ObjectStreamField</code>. Return 257 * -1 if this is smaller, 0 if equal, 1 if greater. Types that are 258 * primitives are "smaller" than object types. If equal, the field names 259 * are compared. 260 */ 261 // REMIND: deprecate? compareTo(Object obj)262 public int compareTo(Object obj) { 263 ObjectStreamField other = (ObjectStreamField) obj; 264 boolean isPrim = isPrimitive(); 265 if (isPrim != other.isPrimitive()) { 266 return isPrim ? -1 : 1; 267 } 268 return name.compareTo(other.name); 269 } 270 271 /** 272 * Return a string that describes this field. 273 */ toString()274 public String toString() { 275 return signature + ' ' + name; 276 } 277 278 /** 279 * Returns field represented by this ObjectStreamField, or null if 280 * ObjectStreamField is not associated with an actual field. 281 */ getField()282 Field getField() { 283 return field; 284 } 285 286 /** 287 * Returns JVM type signature of field (similar to getTypeString, except 288 * that signature strings are returned for primitive fields as well). 289 */ getSignature()290 String getSignature() { 291 return signature; 292 } 293 294 /** 295 * Returns JVM type signature for given class. 296 */ getClassSignature(Class<?> cl)297 private static String getClassSignature(Class<?> cl) { 298 StringBuilder sbuf = new StringBuilder(); 299 while (cl.isArray()) { 300 sbuf.append('['); 301 cl = cl.getComponentType(); 302 } 303 if (cl.isPrimitive()) { 304 if (cl == Integer.TYPE) { 305 sbuf.append('I'); 306 } else if (cl == Byte.TYPE) { 307 sbuf.append('B'); 308 } else if (cl == Long.TYPE) { 309 sbuf.append('J'); 310 } else if (cl == Float.TYPE) { 311 sbuf.append('F'); 312 } else if (cl == Double.TYPE) { 313 sbuf.append('D'); 314 } else if (cl == Short.TYPE) { 315 sbuf.append('S'); 316 } else if (cl == Character.TYPE) { 317 sbuf.append('C'); 318 } else if (cl == Boolean.TYPE) { 319 sbuf.append('Z'); 320 } else if (cl == Void.TYPE) { 321 sbuf.append('V'); 322 } else { 323 throw new InternalError(); 324 } 325 } else { 326 sbuf.append('L' + cl.getName().replace('.', '/') + ';'); 327 } 328 return sbuf.toString(); 329 } 330 } 331