// Copyright 2011 Palantir Technologies
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.palantir.ptoss.util;
import java.beans.IntrospectionException;
import java.lang.reflect.InvocationTargetException;
import com.palantir.ptoss.cinch.core.BindableModel;
import com.palantir.ptoss.cinch.core.BindingContext;
import com.palantir.ptoss.cinch.core.ObjectFieldMethod;
/**
* A class that performs the work of reading and setting values on a bound field.
*
*/
public class Mutator {
/**
* Creates a new Mutator bound to the passed {@link BindingContext}.
* @param context the context for this {@link Mutator}
* @param target the model and field to bind this {@link Mutator} to.
* @return the {@link Mutator}
* @throws IntrospectionException
*/
public static Mutator create(BindingContext context, String target) throws IntrospectionException {
final ObjectFieldMethod getter = context.findGetter(target);
final ObjectFieldMethod setter = context.findSetter(target);
if (getter == null && setter == null) {
throw new IllegalArgumentException("could not find either getter/setter for " + target);
}
BindableModel model = null;
BindableModel getterModel = null;
BindableModel setterModel = null;
if (getter != null) {
getterModel = context.getFieldObject(getter.getField(), BindableModel.class);
model = getterModel;
}
if (setter != null) {
setterModel = context.getFieldObject(setter.getField(), BindableModel.class);
model = setterModel;
}
if (getterModel != null && setterModel != null && getterModel != setterModel) {
throw new IllegalStateException("setter and getter must be on same BindableModel.");
}
return new Mutator(getter, setter, model);
}
private final ObjectFieldMethod getter;
private final ObjectFieldMethod setter;
private final BindableModel model;
/**
* @param getter method to use as the getter for this field
* @param setter method to use as the setter for this field
* @param model model object that this {@link Mutator} applies to.
*/
private Mutator(ObjectFieldMethod getter, ObjectFieldMethod setter, BindableModel model) {
this.getter = getter;
this.setter = setter;
this.model = model;
}
public Object get() throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
if (getter == null) {
throw new IllegalStateException("can not call get() with no getter.");
}
boolean accessible = getter.getMethod().isAccessible();
getter.getMethod().setAccessible(true);
Object value = getter.getMethod().invoke(model);
getter.getMethod().setAccessible(accessible);
return value;
}
public void set(Object value) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
if (setter == null) {
throw new IllegalStateException("can not call set() with no setter.");
}
boolean accessible = setter.getMethod().isAccessible();
setter.getMethod().setAccessible(true);
setter.getMethod().invoke(model, value);
setter.getMethod().setAccessible(accessible);
}
public BindableModel getModel() {
return model;
}
public ObjectFieldMethod getSetter() {
return setter;
}
public ObjectFieldMethod getGetter() {
return getter;
}
}