1. /*
  2. * @(#)ObjectStreamField.java 1.26 01/11/29
  3. *
  4. * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package java.io;
  8. import java.lang.reflect.Field;
  9. /**
  10. * A description of a Serializable field from a Serializable class.
  11. * An array of ObjectStreamFields is used to declare the Serializable
  12. * fields of a class.
  13. *
  14. * @author Roger Riggs
  15. * @version 1.26, 11/29/01
  16. * @see ObjectStreamClass
  17. */
  18. public class ObjectStreamField implements Comparable {
  19. /**
  20. * Create a Serializable field with the specified type.
  21. * This field should be documented with a <code>serialField</code>
  22. * tag.
  23. */
  24. public ObjectStreamField(String n, Class clazz) {
  25. name = n;
  26. this.clazz = clazz;
  27. // Compute the typecode for easy switching
  28. if (clazz.isPrimitive()) {
  29. if (clazz == Integer.TYPE) {
  30. type = 'I';
  31. } else if (clazz == Byte.TYPE) {
  32. type = 'B';
  33. } else if (clazz == Long.TYPE) {
  34. type = 'J';
  35. } else if (clazz == Float.TYPE) {
  36. type = 'F';
  37. } else if (clazz == Double.TYPE) {
  38. type = 'D';
  39. } else if (clazz == Short.TYPE) {
  40. type = 'S';
  41. } else if (clazz == Character.TYPE) {
  42. type = 'C';
  43. } else if (clazz == Boolean.TYPE) {
  44. type = 'Z';
  45. }
  46. } else if (clazz.isArray()) {
  47. type = '[';
  48. typeString = ObjectStreamClass.getSignature(clazz).intern();
  49. } else {
  50. type = 'L';
  51. typeString = ObjectStreamClass.getSignature(clazz).intern();
  52. }
  53. }
  54. /**
  55. * Create a default Serializable field for <code>field</code>.
  56. */
  57. ObjectStreamField(Field field) {
  58. this(field.getName(), field.getType());
  59. this.field = field;
  60. }
  61. /**
  62. * Create an ObjectStreamField containing a reflected Field.
  63. */
  64. ObjectStreamField(String n, char t, Field f, String ts)
  65. {
  66. // System.out.println("new field, " + n + " " + t + " " + ts);
  67. name = n;
  68. type = t;
  69. field = f;
  70. typeString = (ts != null ? ts.intern() : null);
  71. }
  72. /**
  73. * SearchKey constructor.
  74. * @see #compareTo(Object)
  75. */
  76. private ObjectStreamField(String name, boolean isPrimitive) {
  77. // only set fields that compareTo uses for comparison.
  78. this.name = name;
  79. setSearchKeyTypeString(isPrimitive);
  80. }
  81. /**
  82. * Get the name of this field.
  83. */
  84. public String getName() {
  85. return name;
  86. }
  87. /**
  88. * Get the type of the field.
  89. */
  90. public Class getType() {
  91. if (clazz != null)
  92. return clazz;
  93. switch (type) {
  94. case 'B': clazz = Byte.TYPE;
  95. break;
  96. case 'C': clazz = Character.TYPE;
  97. break;
  98. case 'S': clazz = Short.TYPE;
  99. break;
  100. case 'I': clazz = Integer.TYPE;
  101. break;
  102. case 'J': clazz = Long.TYPE;
  103. break;
  104. case 'F': clazz = Float.TYPE;
  105. break;
  106. case 'D': clazz = Double.TYPE;
  107. break;
  108. case 'Z': clazz = Boolean.TYPE;
  109. break;
  110. case '[':
  111. case 'L':
  112. clazz = Object.class;
  113. break;
  114. }
  115. return clazz;
  116. }
  117. /**
  118. * Returns character encoding of field type.
  119. * The encoding is as follows:
  120. * <blockquote><pre>
  121. * B byte
  122. * C char
  123. * D double
  124. * F float
  125. * I int
  126. * J long
  127. * L class or interface
  128. * S short
  129. * Z boolean
  130. * [ array
  131. * </pre></blockquote>
  132. */
  133. public char getTypeCode() {
  134. return type;
  135. }
  136. /**
  137. * Return the JVM type signature.
  138. *
  139. * @returns null if this field has a primitive type.
  140. */
  141. public String getTypeString() {
  142. return typeString;
  143. }
  144. /**
  145. * Offset of field within instance data.
  146. */
  147. public int getOffset() {
  148. return bufoffset;
  149. }
  150. /**
  151. * Offset within instance data.
  152. */
  153. protected void setOffset(int offset) {
  154. bufoffset = offset;
  155. }
  156. /*
  157. * Default constructor creates an empty field.
  158. * Usually used just to get to the sort functions.
  159. */
  160. ObjectStreamField() {
  161. }
  162. /**
  163. * Return true if this field has a primitive type.
  164. */
  165. public boolean isPrimitive() {
  166. return (type != '[' && type != 'L');
  167. }
  168. /**
  169. * Compare this field with another <code>ObjectStreamField</code>.
  170. * Return -1 if this is smaller, 0 if equal, 1 if greater.
  171. * Types that are primitives are "smaller" than object types.
  172. * If equal, the field names are compared.
  173. */
  174. public int compareTo(Object o) {
  175. ObjectStreamField f2 = (ObjectStreamField)o;
  176. boolean thisprim = (this.typeString == null);
  177. boolean otherprim = (f2.typeString == null);
  178. if (thisprim != otherprim) {
  179. return (thisprim ? -1 : 1);
  180. }
  181. return this.name.compareTo(f2.name);
  182. }
  183. /**
  184. * Return a string that describes this field.
  185. */
  186. public String toString() {
  187. if (typeString != null)
  188. return typeString + " " + name;
  189. else
  190. return type + " " + name;
  191. }
  192. /**
  193. * Compare the type of this ObjectStreamField with <code>other</code>.
  194. *
  195. * @returns true if both ObjectStreamFields are serializable compatible.
  196. */
  197. boolean typeEquals(ObjectStreamField other) {
  198. if (other == null || type != other.type)
  199. return false;
  200. /* Optimization: Since interning typeString,
  201. * this short circuit can save some time.
  202. * Also, covers case where both typeStrings are null.
  203. */
  204. if (typeString == other.typeString)
  205. return true;
  206. else
  207. return ObjectStreamClass.compareClassNames(typeString,
  208. other.typeString,
  209. '/');
  210. }
  211. /*
  212. * Return a field.
  213. * @see java.lang.reflect.Field
  214. */
  215. Field getField() {
  216. return field;
  217. }
  218. void setField(Field field) {
  219. this.field = field;
  220. }
  221. /**
  222. * @returns a ObjectStreamField with enough fields set to search
  223. * a list for a matching ObjectStreamField.
  224. * @see #compareTo(Object)
  225. */
  226. static ObjectStreamField constructSearchKey(String fieldName,
  227. Class fieldType)
  228. {
  229. return new ObjectStreamField(fieldName, fieldType.isPrimitive());
  230. }
  231. void setSearchKeyTypeString(boolean isPrimitive) {
  232. typeString = isPrimitive ? null : OBJECT_TYPESTRING;
  233. }
  234. private String name; // the name of the field
  235. private char type; // first byte of the type signature
  236. private Field field; // Reflected field.
  237. private String typeString; // iff object, fully qualified typename containing '/'
  238. private int bufoffset; // offset in the data buffer, or index in objects
  239. private Class clazz; // the type of this field, if has been resolved
  240. /* a string object used for ObjectStreamField search. For search purposes,
  241. * it is sufficient that this string is non-null.
  242. */
  243. private static final String OBJECT_TYPESTRING=new String("");
  244. };