1. /*
  2. * Copyright 2001-2004 The Apache Software Foundation.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package org.apache.commons.beanutils;
  17. import java.io.Serializable;
  18. import java.lang.reflect.Constructor;
  19. import java.lang.reflect.InvocationTargetException;
  20. import java.util.HashMap;
  21. /**
  22. * <p>Minimal implementation of the <code>DynaClass</code> interface. Can be
  23. * used as a convenience base class for more sophisticated implementations.</p> *
  24. * <p><strong>IMPLEMENTATION NOTE</strong> - The <code>DynaBean</code>
  25. * implementation class supplied to our constructor MUST have a one-argument
  26. * constructor of its own that accepts a <code>DynaClass</code>. This is
  27. * used to associate the DynaBean instance with this DynaClass.</p>
  28. *
  29. * @author Craig McClanahan
  30. * @version $Revision: 1.11 $ $Date: 2004/02/28 13:18:33 $
  31. */
  32. public class BasicDynaClass implements DynaClass, Serializable {
  33. // ----------------------------------------------------------- Constructors
  34. /**
  35. * Construct a new BasicDynaClass with default parameters.
  36. */
  37. public BasicDynaClass() {
  38. this(null, null, null);
  39. }
  40. /**
  41. * Construct a new BasicDynaClass with the specified parameters.
  42. *
  43. * @param name Name of this DynaBean class
  44. * @param dynaBeanClass The implementation class for new instances
  45. */
  46. public BasicDynaClass(String name, Class dynaBeanClass) {
  47. this(name, dynaBeanClass, null);
  48. }
  49. /**
  50. * Construct a new BasicDynaClass with the specified parameters.
  51. *
  52. * @param name Name of this DynaBean class
  53. * @param dynaBeanClass The implementation class for new intances
  54. * @param properties Property descriptors for the supported properties
  55. */
  56. public BasicDynaClass(String name, Class dynaBeanClass,
  57. DynaProperty properties[]) {
  58. super();
  59. if (name != null)
  60. this.name = name;
  61. if (dynaBeanClass == null)
  62. dynaBeanClass = BasicDynaBean.class;
  63. setDynaBeanClass(dynaBeanClass);
  64. if (properties != null)
  65. setProperties(properties);
  66. }
  67. // ----------------------------------------------------- Instance Variables
  68. /**
  69. * The constructor of the <code>dynaBeanClass</code> that we will use
  70. * for creating new instances.
  71. */
  72. protected transient Constructor constructor = null;
  73. /**
  74. * The method signature of the constructor we will use to create
  75. * new DynaBean instances.
  76. */
  77. protected static Class constructorTypes[] = { DynaClass.class };
  78. /**
  79. * The argument values to be passed to the constructore we will use
  80. * to create new DynaBean instances.
  81. */
  82. protected Object constructorValues[] = { this };
  83. /**
  84. * The <code>DynaBean</code> implementation class we will use for
  85. * creating new instances.
  86. */
  87. protected Class dynaBeanClass = BasicDynaBean.class;
  88. /**
  89. * The "name" of this DynaBean class.
  90. */
  91. protected String name = this.getClass().getName();
  92. /**
  93. * The set of dynamic properties that are part of this DynaClass.
  94. */
  95. protected DynaProperty properties[] = new DynaProperty[0];
  96. /**
  97. * The set of dynamic properties that are part of this DynaClass,
  98. * keyed by the property name. Individual descriptor instances will
  99. * be the same instances as those in the <code>properties</code> list.
  100. */
  101. protected HashMap propertiesMap = new HashMap();
  102. // ------------------------------------------------------ DynaClass Methods
  103. /**
  104. * Return the name of this DynaClass (analogous to the
  105. * <code>getName()</code> method of <code>java.lang.Class</code), which
  106. * allows the same <code>DynaClass</code> implementation class to support
  107. * different dynamic classes, with different sets of properties.
  108. */
  109. public String getName() {
  110. return (this.name);
  111. }
  112. /**
  113. * Return a property descriptor for the specified property, if it exists;
  114. * otherwise, return <code>null</code>.
  115. *
  116. * @param name Name of the dynamic property for which a descriptor
  117. * is requested
  118. *
  119. * @exception IllegalArgumentException if no property name is specified
  120. */
  121. public DynaProperty getDynaProperty(String name) {
  122. if (name == null) {
  123. throw new IllegalArgumentException
  124. ("No property name specified");
  125. }
  126. return ((DynaProperty) propertiesMap.get(name));
  127. }
  128. /**
  129. * <p>Return an array of <code>ProperyDescriptors</code> for the properties
  130. * currently defined in this DynaClass. If no properties are defined, a
  131. * zero-length array will be returned.</p>
  132. *
  133. * <p><strong>FIXME</strong> - Should we really be implementing
  134. * <code>getBeanInfo()</code> instead, which returns property descriptors
  135. * and a bunch of other stuff?</p>
  136. */
  137. public DynaProperty[] getDynaProperties() {
  138. return (properties);
  139. }
  140. /**
  141. * Instantiate and return a new DynaBean instance, associated
  142. * with this DynaClass.
  143. *
  144. * @exception IllegalAccessException if the Class or the appropriate
  145. * constructor is not accessible
  146. * @exception InstantiationException if this Class represents an abstract
  147. * class, an array class, a primitive type, or void; or if instantiation
  148. * fails for some other reason
  149. */
  150. public DynaBean newInstance()
  151. throws IllegalAccessException, InstantiationException {
  152. try {
  153. // Refind the constructor after a deserialization (if needed)
  154. if (constructor == null) {
  155. setDynaBeanClass(this.dynaBeanClass);
  156. }
  157. // Invoke the constructor to create a new bean instance
  158. return ((DynaBean) constructor.newInstance(constructorValues));
  159. } catch (InvocationTargetException e) {
  160. throw new InstantiationException
  161. (e.getTargetException().getMessage());
  162. }
  163. }
  164. // --------------------------------------------------------- Public Methods
  165. /**
  166. * Return the Class object we will use to create new instances in the
  167. * <code>newInstance()</code> method. This Class <strong>MUST</strong>
  168. * implement the <code>DynaBean</code> interface.
  169. */
  170. public Class getDynaBeanClass() {
  171. return (this.dynaBeanClass);
  172. }
  173. // ------------------------------------------------------ Protected Methods
  174. /**
  175. * Set the Class object we will use to create new instances in the
  176. * <code>newInstance()</code> method. This Class <strong>MUST</strong>
  177. * implement the <code>DynaBean</code> interface.
  178. *
  179. * @param dynaBeanClass The new Class object
  180. *
  181. * @exception IllegalArgumentException if the specified Class does not
  182. * implement the <code>DynaBean</code> interface
  183. */
  184. protected void setDynaBeanClass(Class dynaBeanClass) {
  185. // Validate the argument type specified
  186. if (dynaBeanClass.isInterface())
  187. throw new IllegalArgumentException
  188. ("Class " + dynaBeanClass.getName() +
  189. " is an interface, not a class");
  190. if (!DynaBean.class.isAssignableFrom(dynaBeanClass))
  191. throw new IllegalArgumentException
  192. ("Class " + dynaBeanClass.getName() +
  193. " does not implement DynaBean");
  194. // Identify the Constructor we will use in newInstance()
  195. try {
  196. this.constructor = dynaBeanClass.getConstructor(constructorTypes);
  197. } catch (NoSuchMethodException e) {
  198. throw new IllegalArgumentException
  199. ("Class " + dynaBeanClass.getName() +
  200. " does not have an appropriate constructor");
  201. }
  202. this.dynaBeanClass = dynaBeanClass;
  203. }
  204. /**
  205. * Set the list of dynamic properties supported by this DynaClass.
  206. *
  207. * @param properties List of dynamic properties to be supported
  208. */
  209. protected void setProperties(DynaProperty properties[]) {
  210. this.properties = properties;
  211. propertiesMap.clear();
  212. for (int i = 0; i < properties.length; i++) {
  213. propertiesMap.put(properties[i].getName(), properties[i]);
  214. }
  215. }
  216. }