package sk.stuba.fiit.perconik.utilities.reflect.accessor;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import com.google.common.reflect.Invokable;
import com.google.common.reflect.TypeToken;
import sk.stuba.fiit.perconik.utilities.reflect.accessor.AbstractAccessor.ConstantAccessor;
import sk.stuba.fiit.perconik.utilities.reflect.accessor.AbstractAccessor.FieldAccessor;
import sk.stuba.fiit.perconik.utilities.reflect.accessor.AbstractAccessor.InvokableAccessor;
import static sk.stuba.fiit.perconik.utilities.reflect.accessor.Utilities.checkArgument;
import static sk.stuba.fiit.perconik.utilities.reflect.accessor.Utilities.specialize;
public final class DynamicAccessor<T> {
private DynamicAccessor() {}
public static <T> Accessor<T> ofInstanceConstant(final Object instance, final Class<T> type, final String name) throws IllegalAccessException, NoSuchFieldException {
return ofInstanceConstant(instance, TypeToken.of(type), name);
}
public static <T> Accessor<T> ofInstanceConstant(final Object instance, final TypeToken<T> type, final String name) throws IllegalAccessException, NoSuchFieldException {
Field field = instance.getClass().getField(name);
int modifiers = field.getModifiers();
checkArgument(!Modifier.isStatic(modifiers), "Field %s of %s is static", name, instance.getClass());
checkArgument(Modifier.isFinal(modifiers), "Field %s of %s is not final", name, instance.getClass());
checkArgument(type.equals(TypeToken.of(field.getGenericType())), "Field %s of %s has incorrect type", name, instance.getClass());
return new InstanceConstant<>(type, (T) type.getRawType().cast(field.get(null)));
}
public static <T> Accessor<T> ofInstanceField(final Object instance, final Class<T> type, final String name) throws NoSuchFieldException {
return ofInstanceField(instance, TypeToken.of(type), name);
}
public static <T> Accessor<T> ofInstanceField(final Object instance, final TypeToken<T> type, final String name) throws NoSuchFieldException {
Field field = instance.getClass().getField(name);
int modifiers = field.getModifiers();
checkArgument(!Modifier.isStatic(modifiers), "Field %s of %s is static", name, instance.getClass());
checkArgument(type.equals(TypeToken.of(field.getGenericType())), "Field %s of %s has incorrect type", name, instance.getClass());
return new InstanceField<>(type, field, instance);
}
public static <T> Accessor<T> ofInstanceMethod(final Object instance, final Class<T> type, final String name) throws NoSuchMethodException {
return ofInstanceMethod(instance, TypeToken.of(type), name);
}
public static <T> Accessor<T> ofInstanceMethod(final Object instance, final TypeToken<T> type, final String name, final Object ... arguments) throws NoSuchMethodException {
Invokable<Object, Object> method = (Invokable<Object, Object>) Invokable.from(instance.getClass().getMethod(name));
checkArgument(!method.isStatic(), "Method %s of %s is static", name, instance.getClass());
return new InstanceMethod<>(type, specialize(method, type), instance, arguments);
}
private static final class InstanceConstant<T> extends ConstantAccessor<T> {
InstanceConstant(final TypeToken<T> type, final T constant) {
super(type, constant);
}
}
private static final class InstanceField<T> extends FieldAccessor<T> {
InstanceField(final TypeToken<T> type, final Field field, final Object receiver) {
super(type, field, receiver);
}
}
private static final class InstanceMethod<T> extends InvokableAccessor<T> {
InstanceMethod(final TypeToken<T> type, final Invokable<Object, T> method, final Object receiver, final Object ... arguments) {
super(type, method, receiver, arguments);
}
}
}