1/* 2 * Copyright (c) 2007 Mockito contributors 3 * This program is made available under the terms of the MIT License. 4 */ 5package org.mockito.internal.util.reflection; 6 7import java.lang.reflect.Field; 8import java.lang.reflect.InvocationTargetException; 9import java.lang.reflect.Method; 10import java.util.Locale; 11 12/** 13 * This utility class will call the setter of the property to inject a new value. 14 */ 15public class BeanPropertySetter { 16 17 private static final String SET_PREFIX = "set"; 18 19 private final Object target; 20 private 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