ReadMethodAccessor.java
package fr.sii.ogham.core.util.bean;
import static fr.sii.ogham.core.util.bean.BeanWrapperUtils.getReadMethod;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import fr.sii.ogham.core.exception.util.InvalidPropertyException;
/**
* Access object property using reflection
*
* @author Aurélien Baudet
*
* @param <T>
* The type of the value
*/
public class ReadMethodAccessor<T> implements Accessor<T> {
private static final Object[] NULL_ARGUMENTS = {};
private final Object bean;
private final String name;
private final Method readMethod;
private final Accessor<T> defaultAccessor;
/**
* Initialize the accessor with the provided bean and property name.
*
* <p>
* The read {@link Method} is searched by reflection and using the property
* name.
*
* <p>
* If no read method defined for the property, the {@link FieldAccessor} is
* used.
*
* @param bean
* the bean that will be accessed
* @param name
* the name of the property to access
*/
public ReadMethodAccessor(Object bean, String name) {
this(bean, name, getReadMethod(bean, name), new FieldAccessor<>(bean, name));
}
/**
* Initialize the accessor with the provided bean and property name.
*
* <p>
* The read {@link Method} is directly provided in order to avoid reflection
* scanning.
*
* <p>
* If no read method defined for the property, the {@link FieldAccessor} is
* used.
*
* @param bean
* the bean that will be accessed
* @param name
* the name of the property to access
* @param readMethod
* the getter method obtained through reflection that is used to
* access the property
*/
public ReadMethodAccessor(Object bean, String name, Method readMethod) {
this(bean, name, readMethod, new FieldAccessor<>(bean, name));
}
/**
* Initialize the accessor with the provided bean and property name.
*
* <p>
* The read {@link Method} is directly provided in order to avoid reflection
* scanning.
*
* <p>
* If no read method defined for the property, the
* <code>defaultAccessor</code> parameter is used.
*
* @param bean
* the bean that will be accessed
* @param name
* the name of the property to access
* @param readMethod
* the getter method obtained through reflection that is used to
* access the property. May be null if no read method (no getter)
* exists in the bean class but the property exists
* @param defaultAccessor
* the default accessor if read method is null. May be null if
* only read method is used
*/
public ReadMethodAccessor(Object bean, String name, Method readMethod, Accessor<T> defaultAccessor) {
super();
this.bean = bean;
this.name = name;
this.readMethod = readMethod;
this.defaultAccessor = defaultAccessor;
}
@Override
@SuppressWarnings("unchecked")
public T getValue() {
if (readMethod == null && defaultAccessor == null) {
throw new InvalidPropertyException("Can't get value for property '" + name + "' on bean '" + getClassName() + "': no getter and no default accessor provided.", bean, name);
}
if (readMethod == null) {
return defaultAccessor.getValue();
}
try {
return (T) readMethod.invoke(bean, NULL_ARGUMENTS);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | ClassCastException e) {
throw new InvalidPropertyException("Failed to get value for property '" + name + "' on bean '" + getClassName() + "'", bean, name, e);
}
}
private String getClassName() {
return bean == null ? "null" : bean.getClass().getName();
}
}