1 /*
2 * Copyright 1996-2006 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26 package java.io;
27
28 import java.lang.reflect.Field;
29
30 /**
31 * A description of a Serializable field from a Serializable class. An array
32 * of ObjectStreamFields is used to declare the Serializable fields of a class.
33 *
34 * @author Mike Warres
35 * @author Roger Riggs
36 * @see ObjectStreamClass
37 * @since 1.2
38 */
39 public class ObjectStreamField
40 implements Comparable<Object>
41 {
42
43 /** field name */
44 private final String name;
45 /** canonical JVM signature of field type */
46 private final String signature;
47 /** field type (Object.class if unknown non-primitive type) */
48 private final Class type;
49 /** whether or not to (de)serialize field values as unshared */
50 private final boolean unshared;
51 /** corresponding reflective field object, if any */
52 private final Field field;
53 /** offset of field value in enclosing field group */
54 private int offset = 0;
55
56 /**
57 * Create a Serializable field with the specified type. This field should
58 * be documented with a <code>serialField</code> tag.
59 *
60 * @param name the name of the serializable field
61 * @param type the <code>Class</code> object of the serializable field
62 */
63 public ObjectStreamField(String name, Class<?> type) {
64 this(name, type, false);
65 }
66
67 /**
68 * Creates an ObjectStreamField representing a serializable field with the
69 * given name and type. If unshared is false, values of the represented
70 * field are serialized and deserialized in the default manner--if the
71 * field is non-primitive, object values are serialized and deserialized as
72 * if they had been written and read by calls to writeObject and
73 * readObject. If unshared is true, values of the represented field are
74 * serialized and deserialized as if they had been written and read by
75 * calls to writeUnshared and readUnshared.
76 *
77 * @param name field name
78 * @param type field type
79 * @param unshared if false, write/read field values in the same manner
80 * as writeObject/readObject; if true, write/read in the same
81 * manner as writeUnshared/readUnshared
82 * @since 1.4
83 */
84 public ObjectStreamField(String name, Class<?> type, boolean unshared) {
85 if (name == null) {
86 throw new NullPointerException();
87 }
88 this.name = name;
89 this.type = type;
90 this.unshared = unshared;
91 signature = ObjectStreamClass.getClassSignature(type).intern();
92 field = null;
93 }
94
95 /**
96 * Creates an ObjectStreamField representing a field with the given name,
97 * signature and unshared setting.
98 */
99 ObjectStreamField(String name, String signature, boolean unshared) {
100 if (name == null) {
101 throw new NullPointerException();
102 }
103 this.name = name;
104 this.signature = signature.intern();
105 this.unshared = unshared;
106 field = null;
107
108 switch (signature.charAt(0)) {
109 case 'Z': type = Boolean.TYPE; break;
110 case 'B': type = Byte.TYPE; break;
111 case 'C': type = Character.TYPE; break;
112 case 'S': type = Short.TYPE; break;
113 case 'I': type = Integer.TYPE; break;
114 case 'J': type = Long.TYPE; break;
115 case 'F': type = Float.TYPE; break;
116 case 'D': type = Double.TYPE; break;
117 case 'L':
118 case '[': type = Object.class; break;
119 default: throw new IllegalArgumentException("illegal signature");
120 }
121 }
122
123 /**
124 * Creates an ObjectStreamField representing the given field with the
125 * specified unshared setting. For compatibility with the behavior of
126 * earlier serialization implementations, a "showType" parameter is
127 * necessary to govern whether or not a getType() call on this
128 * ObjectStreamField (if non-primitive) will return Object.class (as
129 * opposed to a more specific reference type).
130 */
131 ObjectStreamField(Field field, boolean unshared, boolean showType) {
132 this.field = field;
133 this.unshared = unshared;
134 name = field.getName();
135 Class ftype = field.getType();
136 type = (showType || ftype.isPrimitive()) ? ftype : Object.class;
137 signature = ObjectStreamClass.getClassSignature(ftype).intern();
138 }
139
140 /**
141 * Get the name of this field.
142 *
143 * @return a <code>String</code> representing the name of the serializable
144 * field
145 */
146 public String getName() {
147 return name;
148 }
149
150 /**
151 * Get the type of the field. If the type is non-primitive and this
152 * <code>ObjectStreamField</code> was obtained from a deserialized {@link
153 * ObjectStreamClass} instance, then <code>Object.class</code> is returned.
154 * Otherwise, the <code>Class</code> object for the type of the field is
155 * returned.
156 *
157 * @return a <code>Class</code> object representing the type of the
158 * serializable field
159 */
160 public Class<?> getType() {
161 return type;
162 }
163
164 /**
165 * Returns character encoding of field type. The encoding is as follows:
166 * <blockquote><pre>
167 * B byte
168 * C char
169 * D double
170 * F float
171 * I int
172 * J long
173 * L class or interface
174 * S short
175 * Z boolean
176 * [ array
177 * </pre></blockquote>
178 *
179 * @return the typecode of the serializable field
180 */
181 // REMIND: deprecate?
182 public char getTypeCode() {
183 return signature.charAt(0);
184 }
185
186 /**
187 * Return the JVM type signature.
188 *
189 * @return null if this field has a primitive type.
190 */
191 // REMIND: deprecate?
192 public String getTypeString() {
193 return isPrimitive() ? null : signature;
194 }
195
196 /**
197 * Offset of field within instance data.
198 *
199 * @return the offset of this field
200 * @see #setOffset
201 */
202 // REMIND: deprecate?
203 public int getOffset() {
204 return offset;
205 }
206
207 /**
208 * Offset within instance data.
209 *
210 * @param offset the offset of the field
211 * @see #getOffset
212 */
213 // REMIND: deprecate?
214 protected void setOffset(int offset) {
215 this.offset = offset;
216 }
217
218 /**
219 * Return true if this field has a primitive type.
220 *
221 * @return true if and only if this field corresponds to a primitive type
222 */
223 // REMIND: deprecate?
224 public boolean isPrimitive() {
225 char tcode = signature.charAt(0);
226 return ((tcode != 'L') && (tcode != '['));
227 }
228
229 /**
230 * Returns boolean value indicating whether or not the serializable field
231 * represented by this ObjectStreamField instance is unshared.
232 *
233 * @since 1.4
234 */
235 public boolean isUnshared() {
236 return unshared;
237 }
238
239 /**
240 * Compare this field with another <code>ObjectStreamField</code>. Return
241 * -1 if this is smaller, 0 if equal, 1 if greater. Types that are
242 * primitives are "smaller" than object types. If equal, the field names
243 * are compared.
244 */
245 // REMIND: deprecate?
246 public int compareTo(Object obj) {
247 ObjectStreamField other = (ObjectStreamField) obj;
248 boolean isPrim = isPrimitive();
249 if (isPrim != other.isPrimitive()) {
250 return isPrim ? -1 : 1;
251 }
252 return name.compareTo(other.name);
253 }
254
255 /**
256 * Return a string that describes this field.
257 */
258 public String toString() {
259 return signature + ' ' + name;
260 }
261
262 /**
263 * Returns field represented by this ObjectStreamField, or null if
264 * ObjectStreamField is not associated with an actual field.
265 */
266 Field getField() {
267 return field;
268 }
269
270 /**
271 * Returns JVM type signature of field (similar to getTypeString, except
272 * that signature strings are returned for primitive fields as well).
273 */
274 String getSignature() {
275 return signature;
276 }
277 }