1 /*
2  * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
3  * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
4  *
5  *
6  *
7  *
8  *
9  *
10  *
11  *
12  *
13  *
14  *
15  *
16  *
17  *
18  *
19  *
20  *
21  *
22  *
23  *
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      */

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      */

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      */

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.classbreak;
122             defaultthrow 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      */

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      */

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
164     public Class<?> getType() {
165         if (System.getSecurityManager() != null) {
166             Class<?> caller = Reflection.getCallerClass();
167             if (ReflectUtil.needsPackageAccessCheck(caller.getClassLoader(), type.getClassLoader())) {
168                 ReflectUtil.checkPackageAccess(type);
169             }
170         }
171         return type;
172     }
173
174     /**
175      * Returns character encoding of field type.  The encoding is as follows:
176      * <blockquote><pre>
177      * B            byte
178      * C            char
179      * D            double
180      * F            float
181      * I            int
182      * J            long
183      * L            class or interface
184      * S            short
185      * Z            boolean
186      * [            array
187      * </pre></blockquote>
188      *
189      * @return  the typecode of the serializable field
190      */

191     // REMIND: deprecate?
192     public char getTypeCode() {
193         return signature.charAt(0);
194     }
195
196     /**
197      * Return the JVM type signature.
198      *
199      * @return  null if this field has a primitive type.
200      */

201     // REMIND: deprecate?
202     public String getTypeString() {
203         return isPrimitive() ? null : signature;
204     }
205
206     /**
207      * Offset of field within instance data.
208      *
209      * @return  the offset of this field
210      * @see #setOffset
211      */

212     // REMIND: deprecate?
213     public int getOffset() {
214         return offset;
215     }
216
217     /**
218      * Offset within instance data.
219      *
220      * @param   offset the offset of the field
221      * @see #getOffset
222      */

223     // REMIND: deprecate?
224     protected void setOffset(int offset) {
225         this.offset = offset;
226     }
227
228     /**
229      * Return true if this field has a primitive type.
230      *
231      * @return  true if and only if this field corresponds to a primitive type
232      */

233     // REMIND: deprecate?
234     public boolean isPrimitive() {
235         char tcode = signature.charAt(0);
236         return ((tcode != 'L') && (tcode != '['));
237     }
238
239     /**
240      * Returns boolean value indicating whether or not the serializable field
241      * represented by this ObjectStreamField instance is unshared.
242      *
243      * @return {@code trueif this field is unshared
244      *
245      * @since 1.4
246      */

247     public boolean isUnshared() {
248         return unshared;
249     }
250
251     /**
252      * Compare this field with another <code>ObjectStreamField</code>.  Return
253      * -1 if this is smaller, 0 if equal, 1 if greater.  Types that are
254      * primitives are "smaller" than object types.  If equal, the field names
255      * are compared.
256      */

257     // REMIND: deprecate?
258     public int compareTo(Object obj) {
259         ObjectStreamField other = (ObjectStreamField) obj;
260         boolean isPrim = isPrimitive();
261         if (isPrim != other.isPrimitive()) {
262             return isPrim ? -1 : 1;
263         }
264         return name.compareTo(other.name);
265     }
266
267     /**
268      * Return a string that describes this field.
269      */

270     public String toString() {
271         return signature + ' ' + name;
272     }
273
274     /**
275      * Returns field represented by this ObjectStreamField, or null if
276      * ObjectStreamField is not associated with an actual field.
277      */

278     Field getField() {
279         return field;
280     }
281
282     /**
283      * Returns JVM type signature of field (similar to getTypeString, except
284      * that signature strings are returned for primitive fields as well).
285      */

286     String getSignature() {
287         return signature;
288     }
289
290     /**
291      * Returns JVM type signature for given class.
292      */

293     private static String getClassSignature(Class<?> cl) {
294         StringBuilder sbuf = new StringBuilder();
295         while (cl.isArray()) {
296             sbuf.append('[');
297             cl = cl.getComponentType();
298         }
299         if (cl.isPrimitive()) {
300             if (cl == Integer.TYPE) {
301                 sbuf.append('I');
302             } else if (cl == Byte.TYPE) {
303                 sbuf.append('B');
304             } else if (cl == Long.TYPE) {
305                 sbuf.append('J');
306             } else if (cl == Float.TYPE) {
307                 sbuf.append('F');
308             } else if (cl == Double.TYPE) {
309                 sbuf.append('D');
310             } else if (cl == Short.TYPE) {
311                 sbuf.append('S');
312             } else if (cl == Character.TYPE) {
313                 sbuf.append('C');
314             } else if (cl == Boolean.TYPE) {
315                 sbuf.append('Z');
316             } else if (cl == Void.TYPE) {
317                 sbuf.append('V');
318             } else {
319                 throw new InternalError();
320             }
321         } else {
322             sbuf.append('L' + cl.getName().replace('.', '/') + ';');
323         }
324         return sbuf.toString();
325     }
326 }
327
Powered by JavaMelody