package tc.oc.commons.core.reflect; import java.lang.reflect.Field; import com.google.common.reflect.TypeToken; public abstract class FieldDelegate { private final Field field; public FieldDelegate(Field field) { this.field = field; field.setAccessible(true); } private Object get(Object obj) { try { return field.get(obj); } catch(IllegalAccessException e) { throw new IllegalAccessError(e.getMessage()); } } private void set(Object obj, Object value) { try { field.set(obj, value); } catch(IllegalAccessException e) { throw new IllegalAccessError(e.getMessage()); } } private static Field findField(Class<?> owner, TypeToken<?> type, String name) { try { final Field field = owner.getDeclaredField(name); final TypeToken<?> actualType = TypeToken.of(field.getGenericType()); if(!type.equals(actualType)) { throw new NoSuchFieldError( "Expected field " + Members.qualifiedName(field) + " to have exact type " + type + " but the actual type is " + actualType ); } return field; } catch(NoSuchFieldException e) { throw new NoSuchFieldError(e.getMessage()); } } public static class Static<T> extends FieldDelegate { public static <T> Static<T> forField(Class<?> owner, Class<T> type, String name) { return forField(owner, TypeToken.of(type), name); } public static <T> Static<T> forField(Class<?> owner, TypeToken<T> type, String name) { final Field field = findField(owner, type, name); if(!Members.isStatic(field)) { throw new NoSuchFieldError("Field " + Members.qualifiedName(field) + " is not static"); } return new Static<>(field); } private Static(Field field) { super(field); } public T get() { return (T) super.get(null); } public void set(T value) { super.set(null, value); } } public static class Instance<O, T> extends FieldDelegate { public static <O, T> Instance<O, T> forField(Class<O> owner, Class<T> type, String name) { return forField(owner, TypeToken.of(type), name); } public static <O, T> Instance<O, T> forField(Class<O> owner, TypeToken<T> type, String name) { final Field field = findField(owner, type, name); if(Members.isStatic(field)) { throw new NoSuchFieldError("Field " + Members.qualifiedName(field) + " is static"); } return new Instance<>(field); } private Instance(Field field) { super(field); } public T get(O instance) { return (T) super.get(instance); } public void set(O instance, T value) { super.set(instance, value); } } }