/* | |
* Copyright (c) 2007 Mockito contributors | |
* This program is made available under the terms of the MIT License. | |
*/ | |
package org.mockito.internal.util.reflection; | |
import java.lang.reflect.Field; | |
import java.lang.reflect.InvocationTargetException; | |
import java.lang.reflect.Method; | |
import java.util.Locale; | |
/** | |
* This utility class will call the setter of the property to inject a new value. | |
*/ | |
public class BeanPropertySetter { | |
private static final String SET_PREFIX = "set"; | |
private final Object target; | |
private final boolean reportNoSetterFound; | |
private final Field field; | |
/** | |
* New BeanPropertySetter | |
* @param target The target on which the setter must be invoked | |
* @param propertyField The field that should be accessed with the setter | |
* @param reportNoSetterFound Allow the set method to raise an Exception if the setter cannot be found | |
*/ | |
public BeanPropertySetter(final Object target, final Field propertyField, boolean reportNoSetterFound) { | |
this.field = propertyField; | |
this.target = target; | |
this.reportNoSetterFound = reportNoSetterFound; | |
} | |
/** | |
* New BeanPropertySetter that don't report failure | |
* @param target The target on which the setter must be invoked | |
* @param propertyField The propertyField that must be accessed through a setter | |
*/ | |
public BeanPropertySetter(final Object target, final Field propertyField) { | |
this(target, propertyField, false); | |
} | |
/** | |
* Set the value to the property represented by this {@link BeanPropertySetter} | |
* @param value the new value to pass to the property setter | |
* @return <code>true</code> if the value has been injected, <code>false</code> otherwise | |
* @throws RuntimeException Can be thrown if the setter threw an exception, if the setter is not accessible | |
* or, if <code>reportNoSetterFound</code> and setter could not be found. | |
*/ | |
public boolean set(final Object value) { | |
AccessibilityChanger changer = new AccessibilityChanger(); | |
Method writeMethod = null; | |
try { | |
writeMethod = target.getClass().getMethod(setterName(field.getName()), field.getType()); | |
changer.enableAccess(writeMethod); | |
writeMethod.invoke(target, value); | |
return true; | |
} catch (InvocationTargetException e) { | |
throw new RuntimeException("Setter '" + writeMethod + "' of '" + target + "' with value '" + value + "' threw exception : '" + e.getTargetException() + "'", e); | |
} catch (IllegalAccessException e) { | |
throw new RuntimeException("Access not authorized on field '" + field + "' of object '" + target + "' with value: '" + value + "'", e); | |
} catch (NoSuchMethodException e) { | |
reportNoSetterFound(); | |
} finally { | |
if(writeMethod != null) { | |
changer.safelyDisableAccess(writeMethod); | |
} | |
} | |
reportNoSetterFound(); | |
return false; | |
} | |
/** | |
* Retrieve the setter name from the field name. | |
* | |
* <p>Implementation is based on the code of {@link java.beans.Introspector}.</p> | |
* | |
* @param fieldName the Field name | |
* @return Setter name. | |
*/ | |
private String setterName(String fieldName) { | |
return new StringBuilder(SET_PREFIX) | |
.append(fieldName.substring(0, 1).toUpperCase(Locale.ENGLISH)) | |
.append(fieldName.substring(1)) | |
.toString(); | |
} | |
private void reportNoSetterFound() { | |
if(reportNoSetterFound) { | |
throw new RuntimeException("Problems setting value on object: [" + target + "] for property : [" + field.getName() + "], setter not found"); | |
} | |
} | |
} |