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