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