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