View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  
19  package org.apache.commons.beanutils;
20  
21  import java.io.Serializable;
22  import java.lang.reflect.InvocationTargetException;
23  
24  
25  /***
26   * <p>Implementation of <code>DynaBean</code> that wraps a standard JavaBean
27   * instance, so that DynaBean APIs can be used to access its properties.</p>
28   *
29   * <p>
30   * The most common use cases for this class involve wrapping an existing java bean.
31   * (This makes it different from the typical use cases for other <code>DynaBean</code>'s.) 
32   * For example:
33   * </p>
34   * <code><pre>
35   *  Object aJavaBean = ...;
36   *  ...
37   *  DynaBean db = new WrapDynaBean(aJavaBean);
38   *  ...
39   * </pre></code>
40   *
41   * <p><strong>IMPLEMENTATION NOTE</strong> - This implementation does not
42   * support the <code>contains()</code> and <code>remove()</code> methods.</p>
43   *
44   * @author Craig McClanahan
45   * @version $Revision: 555824 $ $Date: 2007-07-13 01:27:15 +0100 (Fri, 13 Jul 2007) $
46   */
47  
48  public class WrapDynaBean implements DynaBean, Serializable {
49  
50  
51      // ---------------------------------------------------------- Constructors
52  
53  
54      /***
55       * Construct a new <code>DynaBean</code> associated with the specified
56       * JavaBean instance.
57       *
58       * @param instance JavaBean instance to be wrapped
59       */
60      public WrapDynaBean(Object instance) {
61  
62          super();
63          this.instance = instance;
64          this.dynaClass = (WrapDynaClass)getDynaClass();
65  
66      }
67  
68  
69      // ---------------------------------------------------- Instance Variables
70  
71  
72      /***
73       * The <code>DynaClass</code> "base class" that this DynaBean
74       * is associated with.
75       */
76      protected transient WrapDynaClass dynaClass = null;
77  
78  
79      /***
80       * The JavaBean instance wrapped by this WrapDynaBean.
81       */
82      protected Object instance = null;
83  
84  
85      // ------------------------------------------------------ DynaBean Methods
86  
87  
88      /***
89       * Does the specified mapped property contain a value for the specified
90       * key value?
91       *
92       * @param name Name of the property to check
93       * @param key Name of the key to check
94       * @return <code>true<code> if the mapped property contains a value for
95       * the specified key, otherwise <code>false</code>
96       *
97       * @exception IllegalArgumentException if there is no property
98       *  of the specified name
99       */
100     public boolean contains(String name, String key) {
101 
102         throw new UnsupportedOperationException
103                 ("WrapDynaBean does not support contains()");
104 
105     }
106 
107 
108     /***
109      * Return the value of a simple property with the specified name.
110      *
111      * @param name Name of the property whose value is to be retrieved
112      * @return The property's value
113      *
114      * @exception IllegalArgumentException if there is no property
115      *  of the specified name
116      */
117     public Object get(String name) {
118 
119         Object value = null;
120         try {
121             value = PropertyUtils.getSimpleProperty(instance, name);
122         } catch (InvocationTargetException ite) {
123             Throwable cause = ite.getTargetException();
124             throw new IllegalArgumentException
125                     ("Error reading property '" + name +
126                               "' nested exception - " + cause);
127         } catch (Throwable t) {
128             throw new IllegalArgumentException
129                     ("Error reading property '" + name +
130                               "', exception - " + t);
131         }
132         return (value);
133 
134     }
135 
136 
137     /***
138      * Return the value of an indexed property with the specified name.
139      *
140      * @param name Name of the property whose value is to be retrieved
141      * @param index Index of the value to be retrieved
142      * @return The indexed property's value
143      *
144      * @exception IllegalArgumentException if there is no property
145      *  of the specified name
146      * @exception IllegalArgumentException if the specified property
147      *  exists, but is not indexed
148      * @exception IndexOutOfBoundsException if the specified index
149      *  is outside the range of the underlying property
150      * @exception NullPointerException if no array or List has been
151      *  initialized for this property
152      */
153     public Object get(String name, int index) {
154 
155         Object value = null;
156         try {
157             value = PropertyUtils.getIndexedProperty(instance, name, index);
158         } catch (IndexOutOfBoundsException e) {
159             throw e;
160         } catch (InvocationTargetException ite) {
161             Throwable cause = ite.getTargetException();
162             throw new IllegalArgumentException
163                     ("Error reading indexed property '" + name +
164                               "' nested exception - " + cause);
165         } catch (Throwable t) {
166             throw new IllegalArgumentException
167                     ("Error reading indexed property '" + name +
168                               "', exception - " + t);
169         }
170         return (value);
171 
172     }
173 
174 
175     /***
176      * Return the value of a mapped property with the specified name,
177      * or <code>null</code> if there is no value for the specified key.
178      *
179      * @param name Name of the property whose value is to be retrieved
180      * @param key Key of the value to be retrieved
181      * @return The mapped property's value
182      *
183      * @exception IllegalArgumentException if there is no property
184      *  of the specified name
185      * @exception IllegalArgumentException if the specified property
186      *  exists, but is not mapped
187      */
188     public Object get(String name, String key) {
189 
190         Object value = null;
191         try {
192             value = PropertyUtils.getMappedProperty(instance, name, key);
193         } catch (InvocationTargetException ite) {
194             Throwable cause = ite.getTargetException();
195             throw new IllegalArgumentException
196                     ("Error reading mapped property '" + name +
197                               "' nested exception - " + cause);
198         } catch (Throwable t) {
199             throw new IllegalArgumentException
200                     ("Error reading mapped property '" + name +
201                               "', exception - " + t);
202         }
203         return (value);
204 
205     }
206 
207 
208     /***
209      * Return the <code>DynaClass</code> instance that describes the set of
210      * properties available for this DynaBean.
211      * @return The associated DynaClass
212      */
213     public DynaClass getDynaClass() {
214 
215         if (dynaClass == null) {
216             dynaClass = WrapDynaClass.createDynaClass(instance.getClass());
217         }
218 
219         return (this.dynaClass);
220 
221     }
222 
223 
224     /***
225      * Remove any existing value for the specified key on the
226      * specified mapped property.
227      *
228      * @param name Name of the property for which a value is to
229      *  be removed
230      * @param key Key of the value to be removed
231      *
232      * @exception IllegalArgumentException if there is no property
233      *  of the specified name
234      */
235     public void remove(String name, String key) {
236 
237 
238         throw new UnsupportedOperationException
239                 ("WrapDynaBean does not support remove()");
240 
241     }
242 
243 
244     /***
245      * Set the value of a simple property with the specified name.
246      *
247      * @param name Name of the property whose value is to be set
248      * @param value Value to which this property is to be set
249      *
250      * @exception ConversionException if the specified value cannot be
251      *  converted to the type required for this property
252      * @exception IllegalArgumentException if there is no property
253      *  of the specified name
254      * @exception NullPointerException if an attempt is made to set a
255      *  primitive property to null
256      */
257     public void set(String name, Object value) {
258 
259         try {
260             PropertyUtils.setSimpleProperty(instance, name, value);
261         } catch (InvocationTargetException ite) {
262             Throwable cause = ite.getTargetException();
263             throw new IllegalArgumentException
264                     ("Error setting property '" + name +
265                               "' nested exception -" + cause);
266         } catch (Throwable t) {
267             throw new IllegalArgumentException
268                     ("Error setting property '" + name +
269                               "', exception - " + t);
270         }
271 
272     }
273 
274 
275     /***
276      * Set the value of an indexed property with the specified name.
277      *
278      * @param name Name of the property whose value is to be set
279      * @param index Index of the property to be set
280      * @param value Value to which this property is to be set
281      *
282      * @exception ConversionException if the specified value cannot be
283      *  converted to the type required for this property
284      * @exception IllegalArgumentException if there is no property
285      *  of the specified name
286      * @exception IllegalArgumentException if the specified property
287      *  exists, but is not indexed
288      * @exception IndexOutOfBoundsException if the specified index
289      *  is outside the range of the underlying property
290      */
291     public void set(String name, int index, Object value) {
292 
293         try {
294             PropertyUtils.setIndexedProperty(instance, name, index, value);
295         } catch (IndexOutOfBoundsException e) {
296             throw e;
297         } catch (InvocationTargetException ite) {
298             Throwable cause = ite.getTargetException();
299             throw new IllegalArgumentException
300                     ("Error setting indexed property '" + name +
301                               "' nested exception - " + cause);
302         } catch (Throwable t) {
303             throw new IllegalArgumentException
304                     ("Error setting indexed property '" + name +
305                               "', exception - " + t);
306         }
307 
308     }
309 
310 
311     /***
312      * Set the value of a mapped property with the specified name.
313      *
314      * @param name Name of the property whose value is to be set
315      * @param key Key of the property to be set
316      * @param value Value to which this property is to be set
317      *
318      * @exception ConversionException if the specified value cannot be
319      *  converted to the type required for this property
320      * @exception IllegalArgumentException if there is no property
321      *  of the specified name
322      * @exception IllegalArgumentException if the specified property
323      *  exists, but is not mapped
324      */
325     public void set(String name, String key, Object value) {
326 
327         try {
328             PropertyUtils.setMappedProperty(instance, name, key, value);
329         } catch (InvocationTargetException ite) {
330             Throwable cause = ite.getTargetException();
331             throw new IllegalArgumentException
332                     ("Error setting mapped property '" + name +
333                               "' nested exception - " + cause);
334         } catch (Throwable t) {
335             throw new IllegalArgumentException
336                     ("Error setting mapped property '" + name +
337                               "', exception - " + t);
338         }
339 
340     }
341 
342     /*** 
343      * Gets the bean instance wrapped by this DynaBean.
344      * For most common use cases, 
345      * this object should already be known 
346      * and this method safely be ignored.
347      * But some creators of frameworks using <code>DynaBean</code>'s may 
348      * find this useful.
349      *
350      * @return the java bean Object wrapped by this <code>DynaBean</code>
351      */
352     public Object getInstance() {
353         return instance;
354     }
355 
356 
357     // ------------------------------------------------------ Protected Methods
358 
359 
360     /***
361      * Return the property descriptor for the specified property name.
362      *
363      * @param name Name of the property for which to retrieve the descriptor
364      * @return The descriptor for the specified property
365      *
366      * @exception IllegalArgumentException if this is not a valid property
367      *  name for our DynaClass
368      */
369     protected DynaProperty getDynaProperty(String name) {
370 
371         DynaProperty descriptor = getDynaClass().getDynaProperty(name);
372         if (descriptor == null) {
373             throw new IllegalArgumentException
374                     ("Invalid property name '" + name + "'");
375         }
376         return (descriptor);
377 
378     }
379 
380 
381 }