package sk.stuba.fiit.perconik.utilities.reflect.accessor; import java.lang.reflect.Constructor; 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.createArgument; import static sk.stuba.fiit.perconik.utilities.reflect.accessor.Utilities.specialize; public final class StaticAccessor<T> { private StaticAccessor() {} public static <T> Accessor<T> ofClassConstant(final Class<?> implementation, final Class<T> type, final String name) throws IllegalAccessException, NoSuchFieldException { return ofClassConstant(implementation, TypeToken.of(type), name); } public static <T> Accessor<T> ofClassConstant(final Class<?> implementation, final TypeToken<T> type, final String name) throws IllegalAccessException, NoSuchFieldException { Field field = implementation.getField(name); int modifiers = field.getModifiers(); checkArgument(Modifier.isStatic(modifiers), "Field %s of %s is not static", name, implementation); checkArgument(Modifier.isFinal(modifiers), "Field %s of %s is not final", name, implementation); checkArgument(type.equals(TypeToken.of(field.getGenericType())), "Field %s of %s has incorrect type", name, implementation); return new ClassConstant<>(type, (T) type.getRawType().cast(field.get(null))); } public static <T> Accessor<T> ofClassField(final Class<?> implementation, final Class<T> type, final String name) throws NoSuchFieldException { return ofClassField(implementation, TypeToken.of(type), name); } public static <T> Accessor<T> ofClassField(final Class<?> implementation, final TypeToken<T> type, final String name) throws NoSuchFieldException { Field field = implementation.getField(name); int modifiers = field.getModifiers(); checkArgument(Modifier.isStatic(modifiers), "Field %s of %s is not static", name, implementation); checkArgument(type.equals(TypeToken.of(field.getGenericType())), "Field %s of %s has incorrect type", name, implementation); return new ClassField<>(type, field); } public static <T> Accessor<T> ofClassConstructor(final Class<T> type, final Object ... arguments) throws NoSuchMethodException { return ofClassConstructor(TypeToken.of(type), arguments); } public static <T> Accessor<T> ofClassConstructor(final TypeToken<T> type, final Object ... arguments) throws NoSuchMethodException { Constructor<T> constructor = (Constructor<T>) type.getRawType().getConstructor(); return new ClassConstructor<>(type, (Invokable<Object, T>) Invokable.from(constructor), arguments); } public static <T> Accessor<T> ofClassMethod(final Class<?> implementation, final Class<T> type, final String name, final Object ... arguments) throws NoSuchMethodException { return ofClassMethod(implementation, TypeToken.of(type), name, arguments); } public static <T> Accessor<T> ofClassMethod(final Class<?> implementation, final TypeToken<T> type, final String name, final Object ... arguments) throws NoSuchMethodException { Invokable<Object, Object> method = (Invokable<Object, Object>) Invokable.from(implementation.getMethod(name)); checkArgument(method.isStatic(), "Method %s of %s is not static", name, implementation); return new ClassMethod<>(type, specialize(method, type), arguments); } public static <T> Accessor<T> ofEnumConstant(final Class<T> type, final String name) { return ofEnumConstant(TypeToken.of(type), name); } public static <T> Accessor<T> ofEnumConstant(final TypeToken<T> type, final String name) { Class<T> raw = (Class<T>) type.getRawType(); checkArgument(Enum.class.isAssignableFrom(raw), "Class %s is not an enum", type); T[] constants = raw.getEnumConstants(); for (T constant: constants) { if (name.equals(Enum.class.cast(constant).name())) { return new EnumConstant<>(type, constant); } } throw createArgument("Constant %s not found in enum %s", name, type); } private static final class ClassConstant<T> extends ConstantAccessor<T> { ClassConstant(final TypeToken<T> type, final T constant) { super(type, constant); } } private static final class ClassField<T> extends FieldAccessor<T> { ClassField(final TypeToken<T> type, final Field field) { super(type, field, null); } } private static final class ClassConstructor<T> extends InvokableAccessor<T> { ClassConstructor(final TypeToken<T> type, final Invokable<Object, T> constructor, final Object ... arguments) { super(type, constructor, null, arguments); } } private static final class ClassMethod<T> extends InvokableAccessor<T> { ClassMethod(final TypeToken<T> type, final Invokable<Object, T> method, final Object ... arguments) { super(type, method, arguments); } } private static final class EnumConstant<T> extends ConstantAccessor<T> { EnumConstant(final TypeToken<T> type, final T constant) { super(type, constant); } } }