package sk.stuba.fiit.perconik.utilities.reflect.accessor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import javax.annotation.Nullable;
import com.google.common.reflect.Invokable;
import com.google.common.reflect.TypeToken;
abstract class AbstractAccessor<T> implements Accessor<T> {
final TypeToken<T> token;
AbstractAccessor(final TypeToken<T> token) {
assert token != null;
this.token = token;
}
static class ConstantAccessor<T> extends AbstractAccessor<T> {
final T constant;
ConstantAccessor(final TypeToken<T> type, final T constant) {
super(type);
this.constant = constant;
}
@Override
final T getFailing() {
return this.constant;
}
}
static class FieldAccessor<T> extends AbstractAccessor<T> {
final Field field;
@Nullable
final Object receiver;
FieldAccessor(final TypeToken<T> type, final Field field, @Nullable final Object receiver) {
super(type);
this.field = field;
this.receiver = receiver;
}
@Override
final T getFailing() throws IllegalAccessException {
return (T) this.token.getRawType().cast(this.field.get(this.receiver));
}
}
static class InvokableAccessor<T> extends AbstractAccessor<T> {
final Invokable<Object, T> invokable;
@Nullable
final Object receiver;
final Object[] arguments;
InvokableAccessor(final TypeToken<T> type, final Invokable<Object, T> invokable, @Nullable final Object receiver, final Object ... arguments) {
super(type);
this.invokable = invokable;
this.receiver = receiver;
this.arguments = Arrays.copyOf(arguments, arguments.length);
}
@Override
final T getFailing() throws IllegalAccessException, InvocationTargetException {
return this.invokable.invoke(this.receiver, this.arguments);
}
}
public final T get() {
try {
return this.getFailing();
} catch (ReflectiveOperationException e) {
throw new AccessorInvocationException(e);
}
}
abstract T getFailing() throws ReflectiveOperationException;
}