001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018
019 package org.apache.commons.beanutils;
020
021 import java.io.Serializable;
022 import java.lang.reflect.InvocationTargetException;
023
024
025 /**
026 * <p>Implementation of <code>DynaBean</code> that wraps a standard JavaBean
027 * instance, so that DynaBean APIs can be used to access its properties.</p>
028 *
029 * <p>
030 * The most common use cases for this class involve wrapping an existing java bean.
031 * (This makes it different from the typical use cases for other <code>DynaBean</code>'s.)
032 * For example:
033 * </p>
034 * <code><pre>
035 * Object aJavaBean = ...;
036 * ...
037 * DynaBean db = new WrapDynaBean(aJavaBean);
038 * ...
039 * </pre></code>
040 *
041 * <p><strong>IMPLEMENTATION NOTE</strong> - This implementation does not
042 * support the <code>contains()</code> and <code>remove()</code> methods.</p>
043 *
044 * @author Craig McClanahan
045 * @version $Revision: 555824 $ $Date: 2007-07-13 01:27:15 +0100 (Fri, 13 Jul 2007) $
046 */
047
048 public class WrapDynaBean implements DynaBean, Serializable {
049
050
051 // ---------------------------------------------------------- Constructors
052
053
054 /**
055 * Construct a new <code>DynaBean</code> associated with the specified
056 * JavaBean instance.
057 *
058 * @param instance JavaBean instance to be wrapped
059 */
060 public WrapDynaBean(Object instance) {
061
062 super();
063 this.instance = instance;
064 this.dynaClass = (WrapDynaClass)getDynaClass();
065
066 }
067
068
069 // ---------------------------------------------------- Instance Variables
070
071
072 /**
073 * The <code>DynaClass</code> "base class" that this DynaBean
074 * is associated with.
075 */
076 protected transient WrapDynaClass dynaClass = null;
077
078
079 /**
080 * The JavaBean instance wrapped by this WrapDynaBean.
081 */
082 protected Object instance = null;
083
084
085 // ------------------------------------------------------ DynaBean Methods
086
087
088 /**
089 * Does the specified mapped property contain a value for the specified
090 * key value?
091 *
092 * @param name Name of the property to check
093 * @param key Name of the key to check
094 * @return <code>true<code> if the mapped property contains a value for
095 * the specified key, otherwise <code>false</code>
096 *
097 * @exception IllegalArgumentException if there is no property
098 * of the specified name
099 */
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 }