Coverage Report - org.apache.commons.beanutils.BeanPropertyValueChangeClosure
 
Classes in this File Line Coverage Branch Coverage Complexity
BeanPropertyValueChangeClosure
57%
24/42
42%
6/14
3.667
 
 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.Closure;
 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>Closure</code> that sets a property.</p>
 29  
  * <p>
 30  
  * An implementation of <code>org.apache.commons.collections.Closure</code> that updates
 31  
  * a specified property on the object provided with a specified value.
 32  
  * The <code>BeanPropertyValueChangeClosure</code> constructor takes two parameters which determine
 33  
  * what property will be updated and with what value.
 34  
  * <dl>
 35  
  *    <dt>
 36  
  *       <b><code>
 37  
  *           <pre>public BeanPropertyValueChangeClosure( String propertyName, Object propertyValue )</pre>
 38  
  *       </code></b>
 39  
  *    </dt>
 40  
  *    <dd>
 41  
  *       Will create a <code>Closure</code> that will update an object by setting the property
 42  
  *       specified by <code>propertyName</code> to the value specified by <code>propertyValue</code>.
 43  
  *    </dd>
 44  
  * </dl>
 45  
  *
 46  
  * <p/>
 47  
  * <strong>Note:</strong> Property names can be a simple, nested, indexed, or mapped property as defined by
 48  
  * <code>org.apache.commons.beanutils.PropertyUtils</code>.  If any object in the property path
 49  
  * specified by <code>propertyName</code> is <code>null</code> then the outcome is based on the
 50  
  * value of the <code>ignoreNull</code> attribute.
 51  
  *
 52  
  * <p/>
 53  
  * A typical usage might look like:
 54  
  * <code><pre>
 55  
  * // create the closure
 56  
  * BeanPropertyValueChangeClosure closure =
 57  
  *    new BeanPropertyValueChangeClosure( "activeEmployee", Boolean.TRUE );
 58  
  *
 59  
  * // update the Collection
 60  
  * CollectionUtils.forAllDo( peopleCollection, closure );
 61  
  * </pre></code>
 62  
  * <p/>
 63  
  *
 64  
  * This would take a <code>Collection</code> of person objects and update the
 65  
  * <code>activeEmployee</code> property of each object in the <code>Collection</code> to
 66  
  * <code>true</code>. Assuming...
 67  
  * <ul>
 68  
  *    <li>
 69  
  *       The top level object in the <code>peopleCollection</code> is an object which represents a
 70  
  *       person.
 71  
  *    </li>
 72  
  *    <li>
 73  
  *       The person object has a <code>setActiveEmployee( boolean )</code> method which updates
 74  
  *       the value for the object's <code>activeEmployee</code> property.
 75  
  *    </li>
 76  
  * </ul>
 77  
  *
 78  
  * @author Norm Deane
 79  
  * @see org.apache.commons.beanutils.PropertyUtils
 80  
  * @see org.apache.commons.collections.Closure
 81  
  */
 82  
 public class BeanPropertyValueChangeClosure implements Closure {
 83  
    
 84  
     /** For logging. */
 85  26
     private final Log log = LogFactory.getLog(this.getClass());
 86  
 
 87  
     /**
 88  
      * The name of the property which will be updated when this <code>Closure</code> executes.
 89  
      */
 90  
     private String propertyName;
 91  
 
 92  
     /**
 93  
      * The value that the property specified by <code>propertyName</code>
 94  
      * will be updated to when this <code>Closure</code> executes.
 95  
      */
 96  
     private Object propertyValue;
 97  
 
 98  
     /**
 99  
      * Determines whether <code>null</code> objects in the property path will genenerate an
 100  
      * <code>IllegalArgumentException</code> or not. If set to <code>true</code> then if any objects
 101  
      * in the property path leading up to the target property evaluate to <code>null</code> then the
 102  
      * <code>IllegalArgumentException</code> throw by <code>PropertyUtils</code> will be logged but
 103  
      * not rethrown.  If set to <code>false</code> then if any objects in the property path leading
 104  
      * up to the target property evaluate to <code>null</code> then the
 105  
      * <code>IllegalArgumentException</code> throw by <code>PropertyUtils</code> will be logged and
 106  
      * rethrown.
 107  
      */
 108  
     private boolean ignoreNull;
 109  
 
 110  
     /**
 111  
      * Constructor which takes the name of the property to be changed, the new value to set
 112  
      * the property to, and assumes <code>ignoreNull</code> to be <code>false</code>.
 113  
      *
 114  
      * @param propertyName The name of the property that will be updated with the value specified by
 115  
      * <code>propertyValue</code>.
 116  
      * @param propertyValue The value that <code>propertyName</code> will be set to on the target
 117  
      * object.
 118  
      * @throws IllegalArgumentException If the propertyName provided is null or empty.
 119  
      */
 120  
     public BeanPropertyValueChangeClosure(String propertyName, Object propertyValue) {
 121  25
         this(propertyName, propertyValue, false);
 122  25
     }
 123  
 
 124  
     /**
 125  
      * Constructor which takes the name of the property to be changed, the new value to set
 126  
      * the property to and a boolean which determines whether <code>null</code> objects in the
 127  
      * property path will genenerate an <code>IllegalArgumentException</code> or not.
 128  
      *
 129  
      * @param propertyName The name of the property that will be updated with the value specified by
 130  
      * <code>propertyValue</code>.
 131  
      * @param propertyValue The value that <code>propertyName</code> will be set to on the target
 132  
      * object.
 133  
      * @param ignoreNull Determines whether <code>null</code> objects in the property path will
 134  
      * genenerate an <code>IllegalArgumentException</code> or not.
 135  
      * @throws IllegalArgumentException If the propertyName provided is null or empty.
 136  
      */
 137  
     public BeanPropertyValueChangeClosure(String propertyName, Object propertyValue, boolean ignoreNull) {
 138  26
         super();
 139  
 
 140  26
         if ((propertyName != null) && (propertyName.length() > 0)) {
 141  26
             this.propertyName = propertyName;
 142  26
             this.propertyValue = propertyValue;
 143  26
             this.ignoreNull = ignoreNull;
 144  
         } else {
 145  0
             throw new IllegalArgumentException("propertyName cannot be null or empty");
 146  
         }
 147  26
     }
 148  
 
 149  
     /**
 150  
      * Updates the target object provided using the property update criteria provided when this
 151  
      * <code>BeanPropertyValueChangeClosure</code> was constructed.  If any object in the property
 152  
      * path leading up to the target property is <code>null</code> then the outcome will be based on
 153  
      * the value of the <code>ignoreNull</code> attribute. By default, <code>ignoreNull</code> is
 154  
      * <code>false</code> and would result in an <code>IllegalArgumentException</code> if an object
 155  
      * in the property path leading up to the target property is <code>null</code>.
 156  
      *
 157  
      * @param object The object to be updated.
 158  
      * @throws IllegalArgumentException If an IllegalAccessException, InvocationTargetException, or
 159  
      * NoSuchMethodException is thrown when trying to access the property specified on the object
 160  
      * provided. Or if an object in the property path provided is <code>null</code> and
 161  
      * <code>ignoreNull</code> is set to <code>false</code>.
 162  
      */
 163  
     public void execute(Object object) {
 164  
        
 165  
         try {
 166  26
             PropertyUtils.setProperty(object, propertyName, propertyValue);
 167  11
         } catch (IllegalArgumentException e) {
 168  11
             final String errorMsg = "Unable to execute Closure. Null value encountered in property path...";
 169  
 
 170  11
             if (ignoreNull) {
 171  1
                 log.warn("WARNING: " + errorMsg + e);
 172  
             } else {
 173  10
                 IllegalArgumentException iae = new IllegalArgumentException(errorMsg);
 174  10
                 if (!BeanUtils.initCause(iae, e)) {
 175  0
                     log.error(errorMsg, e);
 176  
                 }
 177  10
                 throw iae;
 178  
             }
 179  0
         } catch (IllegalAccessException e) {
 180  0
             final String errorMsg = "Unable to access the property provided.";
 181  0
             IllegalArgumentException iae = new IllegalArgumentException(errorMsg);
 182  0
             if (!BeanUtils.initCause(iae, e)) {
 183  0
                 log.error(errorMsg, e);
 184  
             }
 185  0
             throw iae;
 186  0
         } catch (InvocationTargetException e) {
 187  0
             final String errorMsg = "Exception occurred in property's getter";
 188  0
             IllegalArgumentException iae = new IllegalArgumentException(errorMsg);
 189  0
             if (!BeanUtils.initCause(iae, e)) {
 190  0
                 log.error(errorMsg, e);
 191  
             }
 192  0
             throw iae;
 193  2
         } catch (NoSuchMethodException e) {
 194  2
             final String errorMsg = "Property not found";
 195  2
             IllegalArgumentException iae = new IllegalArgumentException(errorMsg);
 196  2
             if (!BeanUtils.initCause(iae, e)) {
 197  0
                 log.error(errorMsg, e);
 198  
             }
 199  2
             throw iae;
 200  14
         }
 201  14
     }
 202  
 
 203  
     /**
 204  
      * Returns the name of the property which will be updated when this <code>Closure</code> executes.
 205  
      *
 206  
      * @return The name of the property which will be updated when this <code>Closure</code> executes.
 207  
      */
 208  
     public String getPropertyName() {
 209  0
         return propertyName;
 210  
     }
 211  
 
 212  
     /**
 213  
      * Returns the value that the property specified by <code>propertyName</code>
 214  
      * will be updated to when this <code>Closure</code> executes.
 215  
      *
 216  
      * @return The value that the property specified by <code>propertyName</code>
 217  
      * will be updated to when this <code>Closure</code> executes.
 218  
      */
 219  
     public Object getPropertyValue() {
 220  0
         return propertyValue;
 221  
     }
 222  
 
 223  
     /**
 224  
      * Returns the flag that determines whether <code>null</code> objects in the property path will
 225  
      * genenerate an <code>IllegalArgumentException</code> or not. If set to <code>true</code> then
 226  
      * if any objects in the property path leading up to the target property evaluate to
 227  
      * <code>null</code> then the <code>IllegalArgumentException</code> throw by
 228  
      * <code>PropertyUtils</code> will be logged but not rethrown.  If set to <code>false</code> then
 229  
      * if any objects in the property path leading up to the target property evaluate to
 230  
      * <code>null</code> then the <code>IllegalArgumentException</code> throw by
 231  
      * <code>PropertyUtils</code> will be logged and rethrown.
 232  
      *
 233  
      * @return The flag that determines whether <code>null</code> objects in the property path will
 234  
      * genenerate an <code>IllegalArgumentException</code> or not.
 235  
      */
 236  
     public boolean isIgnoreNull() {
 237  0
         return ignoreNull;
 238  
     }
 239  
 }