Source code: org/apache/commons/beanutils/BeanToPropertyValueTransformer.java
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 package org.apache.commons.beanutils;
18
19 import org.apache.commons.collections.Transformer;
20 import org.apache.commons.logging.Log;
21 import org.apache.commons.logging.LogFactory;
22
23 import java.lang.reflect.InvocationTargetException;
24
25
26 /**
27 * <p><code>Transformer</code> that outputs a property value.</p>
28 *
29 * <p>An implementation of <code>org.apache.commons.collections.Transformer</code> that transforms
30 * the object provided by returning the value of a specified property of the object. The
31 * constructor for <code>BeanToPropertyValueTransformer</code> requires the name of the property
32 * that will be used in the transformation. The property can be a simple, nested, indexed, or
33 * mapped property as defined by <code>org.apache.commons.beanutils.PropertyUtils</code>. If any
34 * object in the property path specified by <code>propertyName</code> is <code>null</code> then the
35 * outcome is based on the value of the <code>ignoreNull</code> attribute.
36 * </p>
37 *
38 * <p>
39 * A typical usage might look like:
40 * <code><pre>
41 * // create the transformer
42 * BeanToPropertyValueTransformer transformer = new BeanToPropertyValueTransformer( "person.address.city" );
43 *
44 * // transform the Collection
45 * Collection peoplesCities = CollectionUtils.collect( peopleCollection, transformer );
46 * </pre></code>
47 * </p>
48 *
49 * <p>
50 * This would take a <code>Collection</code> of person objects and return a <code>Collection</code>
51 * of objects which represents the cities in which each person lived. Assuming...
52 * <ul>
53 * <li>
54 * The top level object in the <code>peeopleCollection</code> is an object which represents a
55 * person.
56 * </li>
57 * <li>
58 * The person object has a <code>getAddress()</code> method which returns an object which
59 * represents a person's address.
60 * </li>
61 * <li>
62 * The address object has a <code>getCity()</code> method which returns an object which
63 * represents the city in which a person lives.
64 * </li>
65 * </ul>
66 *
67 * @author Norm Deane
68 * @see org.apache.commons.beanutils.PropertyUtils
69 * @see org.apache.commons.collections.Transformer
70 */
71 public class BeanToPropertyValueTransformer implements Transformer {
72
73 /** For logging. */
74 private final Log log = LogFactory.getLog(this.getClass());
75
76 /** The name of the property that will be used in the transformation of the object. */
77 private String propertyName;
78
79 /**
80 * <p>Should null objects on the property path throw an <code>IllegalArgumentException</code>?</p>
81 * <p>
82 * Determines whether <code>null</code> objects in the property path will genenerate an
83 * <code>IllegalArgumentException</code> or not. If set to <code>true</code> then if any objects
84 * in the property path evaluate to <code>null</code> then the
85 * <code>IllegalArgumentException</code> throw by <code>PropertyUtils</code> will be logged but
86 * not rethrown and <code>null</code> will be returned. If set to <code>false</code> then if any
87 * objects in the property path evaluate to <code>null</code> then the
88 * <code>IllegalArgumentException</code> throw by <code>PropertyUtils</code> will be logged and
89 * rethrown.
90 * </p>
91 */
92 private boolean ignoreNull;
93
94 /**
95 * Constructs a Transformer which does not ignore nulls.
96 * Constructor which takes the name of the property that will be used in the transformation and
97 * assumes <code>ignoreNull</code> to be <code>false</code>.
98 *
99 * @param propertyName The name of the property that will be used in the transformation.
100 * @throws IllegalArgumentException If the <code>propertyName</code> is <code>null</code> or
101 * empty.
102 */
103 public BeanToPropertyValueTransformer(String propertyName) {
104 this(propertyName, false);
105 }
106
107 /**
108 * Constructs a Transformer and sets ignoreNull.
109 * Constructor which takes the name of the property that will be used in the transformation and
110 * a boolean which determines whether <code>null</code> objects in the property path will
111 * genenerate an <code>IllegalArgumentException</code> or not.
112 *
113 * @param propertyName The name of the property that will be used in the transformation.
114 * @param ignoreNull Determines whether <code>null</code> objects in the property path will
115 * genenerate an <code>IllegalArgumentException</code> or not.
116 * @throws IllegalArgumentException If the <code>propertyName</code> is <code>null</code> or
117 * empty.
118 */
119 public BeanToPropertyValueTransformer(String propertyName, boolean ignoreNull) {
120 super();
121
122 if ((propertyName != null) && (propertyName.length() > 0)) {
123 this.propertyName = propertyName;
124 this.ignoreNull = ignoreNull;
125 } else {
126 throw new IllegalArgumentException(
127 "propertyName cannot be null or empty");
128 }
129 }
130
131 /**
132 * Returns the value of the property named in the transformer's constructor for
133 * the object provided. If any object in the property path leading up to the target property is
134 * <code>null</code> then the outcome will be based on the value of the <code>ignoreNull</code>
135 * attribute. By default, <code>ignoreNull</code> is <code>false</code> and would result in an
136 * <code>IllegalArgumentException</code> if an object in the property path leading up to the
137 * target property is <code>null</code>.
138 *
139 * @param object The object to be transformed.
140 * @return The value of the property named in the transformer's constructor for the object
141 * provided.
142 * @throws IllegalArgumentException If an IllegalAccessException, InvocationTargetException, or
143 * NoSuchMethodException is thrown when trying to access the property specified on the object
144 * provided. Or if an object in the property path provided is <code>null</code> and
145 * <code>ignoreNull</code> is set to <code>false</code>.
146 */
147 public Object transform(Object object) {
148
149 Object propertyValue = null;
150
151 try {
152 propertyValue = PropertyUtils.getProperty(object, propertyName);
153 } catch (IllegalArgumentException e) {
154 final String errorMsg = "Problem during transformation. Null value encountered in property path...";
155
156 if (ignoreNull) {
157 log.warn("WARNING: " + errorMsg, e);
158 } else {
159 log.error("ERROR: " + errorMsg, e);
160 throw e;
161 }
162 } catch (IllegalAccessException e) {
163 final String errorMsg = "Unable to access the property provided.";
164 log.error(errorMsg, e);
165 throw new IllegalArgumentException(errorMsg);
166 } catch (InvocationTargetException e) {
167 final String errorMsg = "Exception occurred in property's getter";
168 log.error(errorMsg, e);
169 throw new IllegalArgumentException(errorMsg);
170 } catch (NoSuchMethodException e) {
171 final String errorMsg = "No property found for name [" +
172 propertyName + "]";
173 log.error(errorMsg, e);
174 throw new IllegalArgumentException(errorMsg);
175 }
176
177 return propertyValue;
178 }
179
180 /**
181 * Returns the name of the property that will be used in the transformation of the bean.
182 *
183 * @return The name of the property that will be used in the transformation of the bean.
184 */
185 public String getPropertyName() {
186 return propertyName;
187 }
188
189 /**
190 * Returns the flag which determines whether <code>null</code> objects in the property path will
191 * genenerate an <code>IllegalArgumentException</code> or not. If set to <code>true</code> then
192 * if any objects in the property path evaluate to <code>null</code> then the
193 * <code>IllegalArgumentException</code> throw by <code>PropertyUtils</code> will be logged but
194 * not rethrown and <code>null</code> will be returned. If set to <code>false</code> then if any
195 * objects in the property path evaluate to <code>null</code> then the
196 * <code>IllegalArgumentException</code> throw by <code>PropertyUtils</code> will be logged and
197 * rethrown.
198 *
199 * @return The flag which determines whether <code>null</code> objects in the property path will
200 * genenerate an <code>IllegalArgumentException</code> or not.
201 */
202 public boolean isIgnoreNull() {
203 return ignoreNull;
204 }
205 }