package com.googlecode.totallylazy.proxy;
import com.googlecode.totallylazy.functions.Function1;
import com.googlecode.totallylazy.reflection.Asm;
import jdk.internal.org.objectweb.asm.tree.ClassNode;
import jdk.internal.org.objectweb.asm.tree.FieldInsnNode;
import jdk.internal.org.objectweb.asm.tree.MethodNode;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import static com.googlecode.totallylazy.reflection.Fields.fields;
import static com.googlecode.totallylazy.reflection.Fields.name;
import static com.googlecode.totallylazy.LazyException.lazyException;
import static com.googlecode.totallylazy.predicates.Predicates.is;
import static com.googlecode.totallylazy.predicates.Predicates.where;
import static com.googlecode.totallylazy.proxy.Generics.getGenericSuperclassType;
import static com.googlecode.totallylazy.proxy.Proxy.proxy;
import static java.lang.Class.forName;
public abstract class FieldOn<T, S> implements Function1<T, S>, InvocationHandler {
private final FieldInvocation<T, S> invocation;
protected final T instance;
public FieldOn() {
Class<T> aClass = getGenericSuperclassType(this.getClass(), 0);
instance = proxy(aClass, this);
invocation = new FieldInvocation<T, S>(readFieldFromByteCode());
}
private Field readFieldFromByteCode() {
try {
ClassNode classNode = Asm.classNode(getClass());
MethodNode constructor = classNode.methods.get(0);
FieldInsnNode fieldInsnNode = Asm.instructions(constructor).safeCast(FieldInsnNode.class).last();
Class<?> aClass = forName(fieldInsnNode.owner.replace('/', '.'));
return fields(aClass).
find(where(name, is(fieldInsnNode.name))).
get();
} catch (Exception e) {
throw lazyException(e);
}
}
protected void get(S s) {
}
@Override
public S call(T t) throws Exception {
return invocation.call(t);
}
public FieldInvocation<T, S> invocation() {
return invocation;
}
public Field field() {
return invocation.field();
}
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
throw new UnsupportedOperationException("Please use CallOn for method invocation");
}
}