/*
* Copyright 2011 Blazebit
*/
package com.blazebit.reflection;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* This class is a lazy setter that can be invoked later. Basically this class
* just holds the target object on which to invoke the setter, the field name
* via which the setter method is determined and the arguments that should be
* passed as parameters to the setter.
*
* @author Christian Beikov
* @since 0.1.2
*/
public class LazySetterMethod {
private final Object target;
private final Object value;
private final PropertyPathExpression<Object, Object> expression;
/**
* Constructs a LazySetterMethod object for the given source object, field
* names as a string separated by '.' (dots) and arguments. Using this
* constructor is equal to #
* {@link LazySetterMethod#LazySetterMethod(java.lang.Object, java.lang.String[], java.lang.Object[]) }
* with the second parameter <code>fieldNames.split("\\.")</code>.
*
* @param target
* The object on which to invoke the getter/setter chain
* @param fieldNames
* The field names which should be used for the setter
* determination
* @param args
* The arguments used for the setter method
*/
@SuppressWarnings("unchecked")
public LazySetterMethod(Object target, String fieldNames, Object value) {
if (target == null) {
throw new NullPointerException("target");
}
this.target = target;
this.value = value;
this.expression = (PropertyPathExpression<Object, Object>) ExpressionUtils
.getExpression(target.getClass(), fieldNames);
}
/**
* Constructs a LazySetterMethod object for the given source object, field
* names as a string separated by '.' (dots) and arguments.
*
* This constructor is equal to #
* {@link LazySetterMethod#LazySetterMethod(java.lang.Object, java.lang.String, java.lang.Object[])}
* except that this constructor shows that #{@link LazyGetterMethod} also
* can be used as parameter. The LazyGetterMethods will be invoked lazily
*
* @param target
* The object on which to invoke the getter/setter chain
* @param fieldNames
* The field names which should be used for the setter
* determination
* @param args
* The arguments used for the setter method
*/
public LazySetterMethod(Object target, String fieldNames,
LazyGetterMethod value) {
this(target, fieldNames, (Object) value);
}
/**
* Invokes the getter/setter chain based on the source object. First of all
* the actual arguments are determined by invoking LazyGetterMethod objects
* that have been passed during construction. Then the getter chain is
* invoked to determine the actual object on which to invoke the setter.
* Finally the setter is invoked with the actual arguments
*
* Example of how the chaining works:
*
* <code>
* class A{
* private B b;
*
* public A(B b){
* this.b = b;
* }
*
* public B getB(){
* return b;
* }
* }
*
* class B{
* private String s;
*
* public B(String s){
* this.s = s;
* }
*
* public void setS(String s){
* this.s = s;
* }
* }
* </code>
*
* <code>
* new LazySetterMethod(new A(new B("")), "b.s", "value").invoke()
* </code>
*
* is equal to
*
* <code>
* new A(new B("")).getB().setS("test");
* </code>
*
* and
*
* <code>
* new LazySetterMethod(new A(new B("")), "b.s", new LazyGetterMethod(new B("lazyValue"), "s").invoke()
* </code>
*
* is equal to
*
* <code>
* new A(new B("")).getB().setS(new B("lazyValue").getS());
* </code>
*
* @throws InvocationTargetException
* #{@link Method#invoke(java.lang.Object, java.lang.Object[]) }
* @throws IllegalAccessException
* #{@link Method#invoke(java.lang.Object, java.lang.Object[]) }
*/
public void invoke() throws InvocationTargetException,
IllegalAccessException {
Object valueToPass = value;
if (valueToPass != null && valueToPass instanceof LazyGetterMethod) {
valueToPass = ((LazyGetterMethod) valueToPass).invoke();
}
expression.setValue(target, valueToPass);
}
}