• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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