1. /*
  2. * @(#)IndexedPropertyDescriptor.java 1.36 03/01/27
  3. *
  4. * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package java.beans;
  8. import java.lang.reflect.*;
  9. /**
  10. * An IndexedPropertyDescriptor describes a property that acts like an
  11. * array and has an indexed read and/or indexed write method to access
  12. * specific elements of the array.
  13. * <p>
  14. * An indexed property may also provide simple non-indexed read and write
  15. * methods. If these are present, they read and write arrays of the type
  16. * returned by the indexed read method.
  17. */
  18. public class IndexedPropertyDescriptor extends PropertyDescriptor {
  19. /**
  20. * This constructor constructs an IndexedPropertyDescriptor for a property
  21. * that follows the standard Java conventions by having getFoo and setFoo
  22. * accessor methods, for both indexed access and array access.
  23. * <p>
  24. * Thus if the argument name is "fred", it will assume that there
  25. * is an indexed reader method "getFred", a non-indexed (array) reader
  26. * method also called "getFred", an indexed writer method "setFred",
  27. * and finally a non-indexed writer method "setFred".
  28. *
  29. * @param propertyName The programmatic name of the property.
  30. * @param beanClass The Class object for the target bean.
  31. * @exception IntrospectionException if an exception occurs during
  32. * introspection.
  33. */
  34. public IndexedPropertyDescriptor(String propertyName, Class beanClass)
  35. throws IntrospectionException {
  36. this(propertyName, beanClass,
  37. "get" + capitalize(propertyName),
  38. "set" + capitalize(propertyName),
  39. "get" + capitalize(propertyName),
  40. "set" + capitalize(propertyName));
  41. }
  42. /**
  43. * This constructor takes the name of a simple property, and method
  44. * names for reading and writing the property, both indexed
  45. * and non-indexed.
  46. *
  47. * @param propertyName The programmatic name of the property.
  48. * @param beanClass The Class object for the target bean.
  49. * @param getterName The name of the method used for reading the property
  50. * values as an array. May be null if the property is write-only
  51. * or must be indexed.
  52. * @param setterName The name of the method used for writing the property
  53. * values as an array. May be null if the property is read-only
  54. * or must be indexed.
  55. * @param indexedGetterName The name of the method used for reading
  56. * an indexed property value.
  57. * May be null if the property is write-only.
  58. * @param indexedSetterName The name of the method used for writing
  59. * an indexed property value.
  60. * May be null if the property is read-only.
  61. * @exception IntrospectionException if an exception occurs during
  62. * introspection.
  63. */
  64. public IndexedPropertyDescriptor(String propertyName, Class beanClass,
  65. String getterName, String setterName,
  66. String indexedGetterName, String indexedSetterName)
  67. throws IntrospectionException {
  68. super(propertyName, beanClass, getterName, setterName);
  69. indexedReadMethod = Introspector.findMethod(beanClass, indexedGetterName, 1);
  70. indexedWriteMethod = Introspector.findMethod(beanClass, indexedSetterName, 2);
  71. findIndexedPropertyType();
  72. }
  73. /**
  74. * This constructor takes the name of a simple property, and Method
  75. * objects for reading and writing the property.
  76. *
  77. * @param propertyName The programmatic name of the property.
  78. * @param getter The method used for reading the property values as an array.
  79. * May be null if the property is write-only or must be indexed.
  80. * @param setter The method used for writing the property values as an array.
  81. * May be null if the property is read-only or must be indexed.
  82. * @param indexedGetter The method used for reading an indexed property value.
  83. * May be null if the property is write-only.
  84. * @param indexedSetter The method used for writing an indexed property value.
  85. * May be null if the property is read-only.
  86. * @exception IntrospectionException if an exception occurs during
  87. * introspection.
  88. */
  89. public IndexedPropertyDescriptor(String propertyName, Method getter, Method setter,
  90. Method indexedGetter, Method indexedSetter)
  91. throws IntrospectionException {
  92. super(propertyName, getter, setter);
  93. indexedReadMethod = indexedGetter;
  94. indexedWriteMethod = indexedSetter;
  95. findIndexedPropertyType();
  96. }
  97. /**
  98. * Gets the method that should be used to read an indexed
  99. * property value.
  100. *
  101. * @return The method that should be used to read an indexed
  102. * property value.
  103. * May return null if the property isn't indexed or is write-only.
  104. */
  105. public Method getIndexedReadMethod() {
  106. return indexedReadMethod;
  107. }
  108. /**
  109. * Sets the method that should be used to read an indexed property value.
  110. *
  111. * @param getter The new indexed getter method.
  112. */
  113. public void setIndexedReadMethod(Method getter) throws IntrospectionException {
  114. indexedReadMethod = getter;
  115. findIndexedPropertyType();
  116. }
  117. /**
  118. * Gets the method that should be used to write an indexed property value.
  119. *
  120. * @return The method that should be used to write an indexed
  121. * property value.
  122. * May return null if the property isn't indexed or is read-only.
  123. */
  124. public Method getIndexedWriteMethod() {
  125. return indexedWriteMethod;
  126. }
  127. /**
  128. * Sets the method that should be used to write an indexed property value.
  129. *
  130. * @param setter The new indexed setter method.
  131. */
  132. public void setIndexedWriteMethod(Method setter) throws IntrospectionException {
  133. indexedWriteMethod = setter;
  134. findIndexedPropertyType();
  135. }
  136. /**
  137. * Gets the Class object of the indexed properties' type.
  138. * This is the type that will be returned by the indexedReadMethod.
  139. *
  140. * @return The Java Class for the indexed properties type. Note that
  141. * the Class may describe a primitive Java type such as "int".
  142. */
  143. public Class getIndexedPropertyType() {
  144. return indexedPropertyType;
  145. }
  146. private void findIndexedPropertyType() throws IntrospectionException {
  147. try {
  148. indexedPropertyType = null;
  149. if (indexedReadMethod != null) {
  150. Class params[] = indexedReadMethod.getParameterTypes();
  151. if (params.length != 1) {
  152. throw new IntrospectionException("bad indexed read method arg count");
  153. }
  154. if (params[0] != Integer.TYPE) {
  155. throw new IntrospectionException("non int index to indexed read method");
  156. }
  157. indexedPropertyType = indexedReadMethod.getReturnType();
  158. if (indexedPropertyType == Void.TYPE) {
  159. throw new IntrospectionException("indexed read method returns void");
  160. }
  161. }
  162. if (indexedWriteMethod != null) {
  163. Class params[] = indexedWriteMethod.getParameterTypes();
  164. if (params.length != 2) {
  165. throw new IntrospectionException("bad indexed write method arg count");
  166. }
  167. if (params[0] != Integer.TYPE) {
  168. throw new IntrospectionException("non int index to indexed write method");
  169. }
  170. if (indexedPropertyType != null && indexedPropertyType != params[1]) {
  171. throw new IntrospectionException(
  172. "type mismatch between indexed read and indexed write methods");
  173. }
  174. indexedPropertyType = params[1];
  175. }
  176. Class propertyType = getPropertyType();
  177. if (propertyType != null && (!propertyType.isArray() ||
  178. propertyType.getComponentType() != indexedPropertyType)) {
  179. throw new IntrospectionException(
  180. "type mismatch between indexed and non-indexed methods");
  181. }
  182. } catch (IntrospectionException ex) {
  183. throw ex;
  184. }
  185. }
  186. /**
  187. * Compares this <code>PropertyDescriptor</code> against the specified object.
  188. * Returns true if the objects are the same. Two <code>PropertyDescriptor</code>s
  189. * are the same if the read, write, property types, property editor and
  190. * flags are equivalent.
  191. *
  192. * @since 1.4
  193. */
  194. public boolean equals(Object obj) {
  195. // Note: This would be identical to PropertyDescriptor but they don't
  196. // share the same fields.
  197. if (obj != null && obj instanceof IndexedPropertyDescriptor) {
  198. IndexedPropertyDescriptor other = (IndexedPropertyDescriptor)obj;
  199. Method otherIndexedReadMethod = other.getIndexedReadMethod();
  200. Method otherIndexedWriteMethod = other.getIndexedWriteMethod();
  201. if (!compareMethods(indexedReadMethod, otherIndexedReadMethod)) {
  202. return false;
  203. }
  204. if (!compareMethods(indexedWriteMethod, otherIndexedWriteMethod)) {
  205. return false;
  206. }
  207. if (indexedPropertyType != other.getIndexedPropertyType()) {
  208. return false;
  209. }
  210. return super.equals(obj);
  211. }
  212. return false;
  213. }
  214. /**
  215. * Package-private constructor.
  216. * Merge two property descriptors. Where they conflict, give the
  217. * second argument (y) priority over the first argumnnt (x).
  218. *
  219. * @param x The first (lower priority) PropertyDescriptor
  220. * @param y The second (higher priority) PropertyDescriptor
  221. */
  222. IndexedPropertyDescriptor(PropertyDescriptor x, PropertyDescriptor y) {
  223. super(x,y);
  224. if (x instanceof IndexedPropertyDescriptor) {
  225. IndexedPropertyDescriptor ix = (IndexedPropertyDescriptor)x;
  226. indexedReadMethod = ix.indexedReadMethod;
  227. indexedWriteMethod = ix.indexedWriteMethod;
  228. indexedPropertyType = ix.indexedPropertyType;
  229. }
  230. if (y instanceof IndexedPropertyDescriptor) {
  231. IndexedPropertyDescriptor iy = (IndexedPropertyDescriptor)y;
  232. if (iy.indexedReadMethod != null) {
  233. indexedReadMethod = iy.indexedReadMethod;
  234. }
  235. if (iy.indexedWriteMethod != null) {
  236. indexedWriteMethod = iy.indexedWriteMethod;
  237. }
  238. indexedPropertyType = iy.indexedPropertyType;
  239. }
  240. }
  241. /*
  242. * Package-private dup constructor
  243. * This must isolate the new object from any changes to the old object.
  244. */
  245. IndexedPropertyDescriptor(IndexedPropertyDescriptor old) {
  246. super(old);
  247. indexedReadMethod = old.indexedReadMethod;
  248. indexedWriteMethod = old.indexedWriteMethod;
  249. indexedPropertyType = old.indexedPropertyType;
  250. }
  251. private Class indexedPropertyType;
  252. private Method indexedReadMethod;
  253. private Method indexedWriteMethod;
  254. }