Coverage Report - org.apache.commons.beanutils.BeanPropertyValueEqualsPredicate
 
Classes in this File Line Coverage Branch Coverage Complexity
BeanPropertyValueEqualsPredicate
59%
26/44
60%
12/20
3.571
 
 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.Predicate;
 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>Predicate</code> that evaluates a property value against a specified value.</p>
 29  
  * <p>
 30  
  * An implementation of <code>org.apache.commons.collections.Predicate</code> that evaluates a
 31  
  * property value on the object provided against a specified value and returns <code>true</code>
 32  
  * if equal; <code>false</code> otherwise.
 33  
  * The <code>BeanPropertyValueEqualsPredicate</code> constructor takes two parameters which
 34  
  * determine what property will be evaluated on the target object and what its expected value should
 35  
  * be.
 36  
  * <dl>
 37  
  *    <dt>
 38  
  *       <strong><code>
 39  
  *           <pre>public BeanPropertyValueEqualsPredicate( String propertyName, Object propertyValue )</pre>
 40  
  *       </code></strong>
 41  
  *    </dt>
 42  
  *    <dd>
 43  
  *       Will create a <code>Predicate</code> that will evaluate the target object and return
 44  
  *       <code>true</code> if the property specified by <code>propertyName</code> has a value which
 45  
  *       is equal to the the value specified by <code>propertyValue</code>. Or return
 46  
  *       <code>false</code> otherwise.
 47  
  *    </dd>
 48  
  * </dl>
 49  
  * </p>
 50  
  * <p>
 51  
  * <strong>Note:</strong> Property names can be a simple, nested, indexed, or mapped property as defined by
 52  
  * <code>org.apache.commons.beanutils.PropertyUtils</code>.  If any object in the property path
 53  
  * specified by <code>propertyName</code> is <code>null</code> then the outcome is based on the
 54  
  * value of the <code>ignoreNull</code> attribute.
 55  
  * </p>
 56  
  * <p>
 57  
  * A typical usage might look like:
 58  
  * <code><pre>
 59  
  * // create the closure
 60  
  * BeanPropertyValueEqualsPredicate predicate =
 61  
  *    new BeanPropertyValueEqualsPredicate( "activeEmployee", Boolean.FALSE );
 62  
  *
 63  
  * // filter the Collection
 64  
  * CollectionUtils.filter( peopleCollection, predicate );
 65  
  * </pre></code>
 66  
  * </p>
 67  
  * <p>
 68  
  * This would take a <code>Collection</code> of person objects and filter out any people whose
 69  
  * <code>activeEmployee</code> property is <code>false</code>. Assuming...
 70  
  * <ul>
 71  
  *    <li>
 72  
  *       The top level object in the <code>peeopleCollection</code> is an object which represents a
 73  
  *       person.
 74  
  *    </li>
 75  
  *    <li>
 76  
  *       The person object has a <code>getActiveEmployee()</code> method which returns
 77  
  *       the boolean value for the object's <code>activeEmployee</code> property.
 78  
  *    </li>
 79  
  * </ul>
 80  
  * </p>
 81  
  * <p>
 82  
  * Another typical usage might look like:
 83  
  * <code><pre>
 84  
  * // create the closure
 85  
  * BeanPropertyValueEqualsPredicate predicate =
 86  
  *    new BeanPropertyValueEqualsPredicate( "personId", "456-12-1234" );
 87  
  *
 88  
  * // search the Collection
 89  
  * CollectionUtils.find( peopleCollection, predicate );
 90  
  * </pre><code>
 91  
  * </p>
 92  
  * <p>
 93  
  * This would search a <code>Collection</code> of person objects and return the first object whose
 94  
  * <code>personId</code> property value equals <code>456-12-1234</code>. Assuming...
 95  
  * <ul>
 96  
  *    <li>
 97  
  *       The top level object in the <code>peeopleCollection</code> is an object which represents a
 98  
  *       person.
 99  
  *    </li>
 100  
  *    <li>
 101  
  *       The person object has a <code>getPersonId()</code> method which returns
 102  
  *       the value for the object's <code>personId</code> property.
 103  
  *    </li>
 104  
  * </ul>
 105  
  * </p>
 106  
  *
 107  
  * @author Norm Deane
 108  
  * @see org.apache.commons.beanutils.PropertyUtils
 109  
  * @see org.apache.commons.collections.Predicate
 110  
  */
 111  
 public class BeanPropertyValueEqualsPredicate implements Predicate {
 112  
    
 113  
     /** For logging. */
 114  21
     private final Log log = LogFactory.getLog(this.getClass());
 115  
 
 116  
     /**
 117  
      * The name of the property which will be evaluated when this <code>Predicate</code> is executed.
 118  
      */
 119  
     private String propertyName;
 120  
 
 121  
     /**
 122  
      * The value that the property specified by <code>propertyName</code>
 123  
      * will be compared to when this <code>Predicate</code> executes.
 124  
      */
 125  
     private Object propertyValue;
 126  
 
 127  
     /**
 128  
      * <p>Should <code>null</code> objects in the property path be ignored?</p>
 129  
      * <p>
 130  
      * Determines whether <code>null</code> objects in the property path will genenerate an
 131  
      * <code>IllegalArgumentException</code> or not. If set to <code>true</code> then if any objects
 132  
      * in the property path evaluate to <code>null</code> then the
 133  
      * <code>IllegalArgumentException</code> throw by <code>PropertyUtils</code> will be logged but
 134  
      * not rethrown and <code>false</code> will be returned.  If set to <code>false</code> then if
 135  
      * any objects in the property path evaluate to <code>null</code> then the
 136  
      * <code>IllegalArgumentException</code> throw by <code>PropertyUtils</code> will be logged and
 137  
      * rethrown.
 138  
      * </p>
 139  
      */
 140  
     private boolean ignoreNull;
 141  
 
 142  
     /**
 143  
      * Constructor which takes the name of the property, its expected value to be used in evaluation,
 144  
      * and assumes <code>ignoreNull</code> to be <code>false</code>.
 145  
      *
 146  
      * @param propertyName The name of the property that will be evaluated against the expected value.
 147  
      * @param propertyValue The value to use in object evaluation.
 148  
      * @throws IllegalArgumentException If the property name provided is null or empty.
 149  
      */
 150  
     public BeanPropertyValueEqualsPredicate(String propertyName, Object propertyValue) {
 151  20
         this(propertyName, propertyValue, false);
 152  20
     }
 153  
 
 154  
     /**
 155  
      * Constructor which takes the name of the property, its expected value
 156  
      * to be used in evaluation, and a boolean which determines whether <code>null</code> objects in
 157  
      * the property path will genenerate an <code>IllegalArgumentException</code> or not.
 158  
      *
 159  
      * @param propertyName The name of the property that will be evaluated against the expected value.
 160  
      * @param propertyValue The value to use in object evaluation.
 161  
      * @param ignoreNull Determines whether <code>null</code> objects in the property path will
 162  
      * genenerate an <code>IllegalArgumentException</code> or not.
 163  
      * @throws IllegalArgumentException If the property name provided is null or empty.
 164  
      */
 165  
     public BeanPropertyValueEqualsPredicate(String propertyName, Object propertyValue, boolean ignoreNull) {
 166  21
         super();
 167  
 
 168  21
         if ((propertyName != null) && (propertyName.length() > 0)) {
 169  21
             this.propertyName = propertyName;
 170  21
             this.propertyValue = propertyValue;
 171  21
             this.ignoreNull = ignoreNull;
 172  
         } else {
 173  0
             throw new IllegalArgumentException("propertyName cannot be null or empty");
 174  
         }
 175  21
     }
 176  
 
 177  
     /**
 178  
      * Evaulates the object provided against the criteria specified when this
 179  
      * <code>BeanPropertyValueEqualsPredicate</code> was constructed.  Equality is based on
 180  
      * either reference or logical equality as defined by the property object's equals method. If
 181  
      * any object in the property path leading up to the target property is <code>null</code> then
 182  
      * the outcome will be based on the value of the <code>ignoreNull</code> attribute. By default,
 183  
      * <code>ignoreNull</code> is <code>false</code> and would result in an
 184  
      * <code>IllegalArgumentException</code> if an object in the property path leading up to the
 185  
      * target property is <code>null</code>.
 186  
      *
 187  
      * @param object The object to be evaluated.
 188  
      * @return True if the object provided meets all the criteria for this <code>Predicate</code>;
 189  
      * false otherwise.
 190  
      * @throws IllegalArgumentException If an IllegalAccessException, InvocationTargetException, or
 191  
      * NoSuchMethodException is thrown when trying to access the property specified on the object
 192  
      * provided. Or if an object in the property path provided is <code>null</code> and
 193  
      * <code>ignoreNull</code> is set to <code>false</code>.
 194  
      */
 195  
     public boolean evaluate(Object object) {
 196  
        
 197  32
         boolean evaluation = false;
 198  
 
 199  
         try {
 200  32
             evaluation = evaluateValue(propertyValue,
 201  
                     PropertyUtils.getProperty(object, propertyName));
 202  2
         } catch (IllegalArgumentException e) {
 203  2
             final String errorMsg = "Problem during evaluation. Null value encountered in property path...";
 204  
 
 205  2
             if (ignoreNull) {
 206  1
                 log.warn("WARNING: " + errorMsg + e);
 207  
             } else {
 208  1
                 IllegalArgumentException iae = new IllegalArgumentException(errorMsg);
 209  1
                 if (!BeanUtils.initCause(iae, e)) {
 210  0
                     log.error(errorMsg, e);
 211  
                 }
 212  1
                 throw iae;
 213  
             }
 214  0
         } catch (IllegalAccessException e) {
 215  0
             final String errorMsg = "Unable to access the property provided.";
 216  0
             IllegalArgumentException iae = new IllegalArgumentException(errorMsg);
 217  0
             if (!BeanUtils.initCause(iae, e)) {
 218  0
                 log.error(errorMsg, e);
 219  
             }
 220  0
             throw iae;
 221  0
         } catch (InvocationTargetException e) {
 222  0
             final String errorMsg = "Exception occurred in property's getter";
 223  0
             IllegalArgumentException iae = new IllegalArgumentException(errorMsg);
 224  0
             if (!BeanUtils.initCause(iae, e)) {
 225  0
                 log.error(errorMsg, e);
 226  
             }
 227  0
             throw iae;
 228  2
         } catch (NoSuchMethodException e) {
 229  2
             final String errorMsg = "Property not found.";
 230  2
             IllegalArgumentException iae = new IllegalArgumentException(errorMsg);
 231  2
             if (!BeanUtils.initCause(iae, e)) {
 232  0
                 log.error(errorMsg, e);
 233  
             }
 234  2
             throw iae;
 235  28
         }
 236  
 
 237  28
         return evaluation;
 238  
     }
 239  
 
 240  
     /**
 241  
      * Utility method which evaluates whether the actual property value equals the expected property
 242  
      * value.
 243  
      *
 244  
      * @param expected The expected value.
 245  
      * @param actual The actual value.
 246  
      * @return True if they are equal; false otherwise.
 247  
      */
 248  
     protected boolean evaluateValue(Object expected, Object actual) {
 249  27
         return (expected == actual) || ((expected != null) && expected.equals(actual));
 250  
     }
 251  
 
 252  
     /**
 253  
      * Returns the name of the property which will be evaluated when this <code>Predicate</code> is
 254  
      * executed.
 255  
      *
 256  
      * @return The name of the property which will be evaluated when this <code>Predicate</code> is
 257  
      * executed.
 258  
      */
 259  
     public String getPropertyName() {
 260  0
         return propertyName;
 261  
     }
 262  
 
 263  
     /**
 264  
      * Returns the value that the property specified by <code>propertyName</code> will be compared to
 265  
      * when this <code>Predicate</code> executes.
 266  
      *
 267  
      * @return The value that the property specified by <code>propertyName</code> will be compared to
 268  
      * when this <code>Predicate</code> executes.
 269  
      */
 270  
     public Object getPropertyValue() {
 271  0
         return propertyValue;
 272  
     }
 273  
 
 274  
     /**
 275  
      * Returns the flag which determines whether <code>null</code> objects in the property path will
 276  
      * genenerate an <code>IllegalArgumentException</code> or not. If set to <code>true</code> then
 277  
      * if any objects in the property path evaluate to <code>null</code> then the
 278  
      * <code>IllegalArgumentException</code> throw by <code>PropertyUtils</code> will be logged but
 279  
      * not rethrown and <code>false</code> will be returned.  If set to <code>false</code> then if
 280  
      * any objects in the property path evaluate to <code>null</code> then the
 281  
      * <code>IllegalArgumentException</code> throw by <code>PropertyUtils</code> will be logged and
 282  
      * rethrown.
 283  
      *
 284  
      * @return The flag which determines whether <code>null</code> objects in the property path will
 285  
      * genenerate an <code>IllegalArgumentException</code> or not.
 286  
      */
 287  
     public boolean isIgnoreNull() {
 288  0
         return ignoreNull;
 289  
     }
 290  
 }