View Javadoc

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  
17  
18  package org.apache.commons.beanutils;
19  
20  
21  import java.io.Serializable;
22  import java.lang.reflect.Constructor;
23  import java.lang.reflect.InvocationTargetException;
24  import java.util.HashMap;
25  
26  
27  /**
28   * <p>Minimal implementation of the <code>DynaClass</code> interface.  Can be
29   * used as a convenience base class for more sophisticated implementations.</p> *
30   * <p><strong>IMPLEMENTATION NOTE</strong> - The <code>DynaBean</code>
31   * implementation class supplied to our constructor MUST have a one-argument
32   * constructor of its own that accepts a <code>DynaClass</code>.  This is
33   * used to associate the DynaBean instance with this DynaClass.</p>
34   *
35   * @author Craig McClanahan
36   * @version $Revision: 1.11 $ $Date: 2004/02/28 13:18:33 $
37   */
38  
39  public class BasicDynaClass implements DynaClass, Serializable {
40  
41  
42      // ----------------------------------------------------------- Constructors
43  
44  
45      /**
46       * Construct a new BasicDynaClass with default parameters.
47       */
48      public BasicDynaClass() {
49  
50          this(null, null, null);
51  
52      }
53  
54  
55      /**
56       * Construct a new BasicDynaClass with the specified parameters.
57       *
58       * @param name Name of this DynaBean class
59       * @param dynaBeanClass The implementation class for new instances
60       */
61      public BasicDynaClass(String name, Class dynaBeanClass) {
62  
63          this(name, dynaBeanClass, null);
64  
65      }
66  
67  
68      /**
69       * Construct a new BasicDynaClass with the specified parameters.
70       *
71       * @param name Name of this DynaBean class
72       * @param dynaBeanClass The implementation class for new intances
73       * @param properties Property descriptors for the supported properties
74       */
75      public BasicDynaClass(String name, Class dynaBeanClass,
76                            DynaProperty properties[]) {
77  
78          super();
79          if (name != null)
80              this.name = name;
81          if (dynaBeanClass == null)
82              dynaBeanClass = BasicDynaBean.class;
83          setDynaBeanClass(dynaBeanClass);
84          if (properties != null)
85              setProperties(properties);
86  
87      }
88  
89  
90      // ----------------------------------------------------- Instance Variables
91  
92  
93      /**
94       * The constructor of the <code>dynaBeanClass</code> that we will use
95       * for creating new instances.
96       */
97      protected transient Constructor constructor = null;
98  
99  
100     /**
101      * The method signature of the constructor we will use to create
102      * new DynaBean instances.
103      */
104     protected static Class constructorTypes[] = { DynaClass.class };
105 
106 
107     /**
108      * The argument values to be passed to the constructore we will use
109      * to create new DynaBean instances.
110      */
111     protected Object constructorValues[] = { this };
112 
113 
114     /**
115      * The <code>DynaBean</code> implementation class we will use for
116      * creating new instances.
117      */
118     protected Class dynaBeanClass = BasicDynaBean.class;
119 
120 
121     /**
122      * The "name" of this DynaBean class.
123      */
124     protected String name = this.getClass().getName();
125 
126 
127     /**
128      * The set of dynamic properties that are part of this DynaClass.
129      */
130     protected DynaProperty properties[] = new DynaProperty[0];
131 
132 
133     /**
134      * The set of dynamic properties that are part of this DynaClass,
135      * keyed by the property name.  Individual descriptor instances will
136      * be the same instances as those in the <code>properties</code> list.
137      */
138     protected HashMap propertiesMap = new HashMap();
139 
140 
141     // ------------------------------------------------------ DynaClass Methods
142 
143 
144     /**
145      * Return the name of this DynaClass (analogous to the
146      * <code>getName()</code> method of <code>java.lang.Class</code), which
147      * allows the same <code>DynaClass</code> implementation class to support
148      * different dynamic classes, with different sets of properties.
149      */
150     public String getName() {
151 
152         return (this.name);
153 
154     }
155 
156 
157     /**
158      * Return a property descriptor for the specified property, if it exists;
159      * otherwise, return <code>null</code>.
160      *
161      * @param name Name of the dynamic property for which a descriptor
162      *  is requested
163      *
164      * @exception IllegalArgumentException if no property name is specified
165      */
166     public DynaProperty getDynaProperty(String name) {
167 
168         if (name == null) {
169             throw new IllegalArgumentException
170                     ("No property name specified");
171         }
172         return ((DynaProperty) propertiesMap.get(name));
173 
174     }
175 
176 
177     /**
178      * <p>Return an array of <code>ProperyDescriptors</code> for the properties
179      * currently defined in this DynaClass.  If no properties are defined, a
180      * zero-length array will be returned.</p>
181      *
182      * <p><strong>FIXME</strong> - Should we really be implementing
183      * <code>getBeanInfo()</code> instead, which returns property descriptors
184      * and a bunch of other stuff?</p>
185      */
186     public DynaProperty[] getDynaProperties() {
187 
188         return (properties);
189 
190     }
191 
192 
193     /**
194      * Instantiate and return a new DynaBean instance, associated
195      * with this DynaClass.
196      *
197      * @exception IllegalAccessException if the Class or the appropriate
198      *  constructor is not accessible
199      * @exception InstantiationException if this Class represents an abstract
200      *  class, an array class, a primitive type, or void; or if instantiation
201      *  fails for some other reason
202      */
203     public DynaBean newInstance()
204             throws IllegalAccessException, InstantiationException {
205 
206         try {
207             // Refind the constructor after a deserialization (if needed)
208             if (constructor == null) {
209                 setDynaBeanClass(this.dynaBeanClass);
210             }
211             // Invoke the constructor to create a new bean instance
212             return ((DynaBean) constructor.newInstance(constructorValues));
213         } catch (InvocationTargetException e) {
214             throw new InstantiationException
215                     (e.getTargetException().getMessage());
216         }
217 
218     }
219 
220 
221     // --------------------------------------------------------- Public Methods
222 
223 
224     /**
225      * Return the Class object we will use to create new instances in the
226      * <code>newInstance()</code> method.  This Class <strong>MUST</strong>
227      * implement the <code>DynaBean</code> interface.
228      */
229     public Class getDynaBeanClass() {
230 
231         return (this.dynaBeanClass);
232 
233     }
234 
235 
236     // ------------------------------------------------------ Protected Methods
237 
238 
239     /**
240      * Set the Class object we will use to create new instances in the
241      * <code>newInstance()</code> method.  This Class <strong>MUST</strong>
242      * implement the <code>DynaBean</code> interface.
243      *
244      * @param dynaBeanClass The new Class object
245      *
246      * @exception IllegalArgumentException if the specified Class does not
247      *  implement the <code>DynaBean</code> interface
248      */
249     protected void setDynaBeanClass(Class dynaBeanClass) {
250 
251         // Validate the argument type specified
252         if (dynaBeanClass.isInterface())
253             throw new IllegalArgumentException
254                     ("Class " + dynaBeanClass.getName() +
255                     " is an interface, not a class");
256         if (!DynaBean.class.isAssignableFrom(dynaBeanClass))
257             throw new IllegalArgumentException
258                     ("Class " + dynaBeanClass.getName() +
259                     " does not implement DynaBean");
260 
261         // Identify the Constructor we will use in newInstance()
262         try {
263             this.constructor = dynaBeanClass.getConstructor(constructorTypes);
264         } catch (NoSuchMethodException e) {
265             throw new IllegalArgumentException
266                     ("Class " + dynaBeanClass.getName() +
267                     " does not have an appropriate constructor");
268         }
269         this.dynaBeanClass = dynaBeanClass;
270 
271     }
272 
273 
274     /**
275      * Set the list of dynamic properties supported by this DynaClass.
276      *
277      * @param properties List of dynamic properties to be supported
278      */
279     protected void setProperties(DynaProperty properties[]) {
280 
281         this.properties = properties;
282         propertiesMap.clear();
283         for (int i = 0; i < properties.length; i++) {
284             propertiesMap.put(properties[i].getName(), properties[i]);
285         }
286 
287     }
288 
289 
290 }