Home | History | Annotate | Download | only in reflection
      1 /*
      2  * Copyright (c) 2007 Mockito contributors
      3  * This program is made available under the terms of the MIT License.
      4  */
      5 package org.mockito.internal.util.reflection;
      6 
      7 import java.lang.reflect.Field;
      8 import java.lang.reflect.InvocationTargetException;
      9 import java.lang.reflect.Method;
     10 import java.util.Locale;
     11 
     12 /**
     13  * This utility class will call the setter of the property to inject a new value.
     14  */
     15 public class BeanPropertySetter {
     16 
     17     private static final String SET_PREFIX = "set";
     18 
     19     private final Object target;
     20     private final boolean reportNoSetterFound;
     21     private final Field field;
     22 
     23     /**
     24      * New BeanPropertySetter
     25      * @param target The target on which the setter must be invoked
     26      * @param propertyField The field that should be accessed with the setter
     27      * @param reportNoSetterFound Allow the set method to raise an Exception if the setter cannot be found
     28      */
     29     public BeanPropertySetter(final Object target, final Field propertyField, boolean reportNoSetterFound) {
     30         this.field = propertyField;
     31         this.target = target;
     32         this.reportNoSetterFound = reportNoSetterFound;
     33     }
     34 
     35     /**
     36      * New BeanPropertySetter that don't report failure
     37      * @param target The target on which the setter must be invoked
     38      * @param propertyField The propertyField that must be accessed through a setter
     39      */
     40     public BeanPropertySetter(final Object target, final Field propertyField) {
     41         this(target, propertyField, false);
     42     }
     43 
     44     /**
     45      * Set the value to the property represented by this {@link BeanPropertySetter}
     46      * @param value the new value to pass to the property setter
     47      * @return <code>true</code> if the value has been injected, <code>false</code> otherwise
     48      * @throws RuntimeException Can be thrown if the setter threw an exception, if the setter is not accessible
     49      *          or, if <code>reportNoSetterFound</code> and setter could not be found.
     50      */
     51     public boolean set(final Object value) {
     52 
     53         AccessibilityChanger changer = new AccessibilityChanger();
     54         Method writeMethod = null;
     55         try {
     56             writeMethod = target.getClass().getMethod(setterName(field.getName()), field.getType());
     57 
     58             changer.enableAccess(writeMethod);
     59             writeMethod.invoke(target, value);
     60             return true;
     61         } catch (InvocationTargetException e) {
     62             throw new RuntimeException("Setter '" + writeMethod + "' of '" + target + "' with value '" + value + "' threw exception : '" + e.getTargetException() + "'", e);
     63         } catch (IllegalAccessException e) {
     64             throw new RuntimeException("Access not authorized on field '" + field + "' of object '" + target + "' with value: '" + value + "'", e);
     65         } catch (NoSuchMethodException e) {
     66             reportNoSetterFound();
     67         } finally {
     68             if(writeMethod != null) {
     69                 changer.safelyDisableAccess(writeMethod);
     70             }
     71         }
     72 
     73         reportNoSetterFound();
     74         return false;
     75     }
     76 
     77     /**
     78      * Retrieve the setter name from the field name.
     79      *
     80      * <p>Implementation is based on the code of {@link java.beans.Introspector}.</p>
     81      *
     82      * @param fieldName the Field name
     83      * @return Setter name.
     84      */
     85     private String setterName(String fieldName) {
     86         return new StringBuilder(SET_PREFIX)
     87                 .append(fieldName.substring(0, 1).toUpperCase(Locale.ENGLISH))
     88                 .append(fieldName.substring(1))
     89                 .toString();
     90     }
     91 
     92     private void reportNoSetterFound() {
     93         if(reportNoSetterFound) {
     94             throw new RuntimeException("Problems setting value on object: [" + target + "] for property : [" + field.getName() + "], setter not found");
     95         }
     96     }
     97 
     98 }
     99