package sk.stuba.fiit.perconik.utilities.reflect; import java.lang.annotation.Annotation; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.Set; import javax.annotation.Nullable; import com.google.common.base.Function; import static java.util.Arrays.asList; import static com.google.common.collect.Lists.newLinkedList; import static com.google.common.collect.Sets.newHashSet; import static com.google.common.collect.Sets.newLinkedHashSet; public final class Reflections { private Reflections() {} private enum ToAnnotationTypeFunction implements Function<Annotation, Class<? extends Annotation>> { INSTANCE; public Class<? extends Annotation> apply(@Nullable final Annotation annotation) { return annotation != null ? annotation.annotationType() : null; } @Override public String toString() { return Classes.toMethodName(this.getClass()); } } private enum ToClassFunction implements Function<Object, Class<? extends Object>> { INSTANCE; public Class<? extends Object> apply(@Nullable final Object object) { return object != null ? object.getClass() : null; } @Override public String toString() { return Classes.toMethodName(this.getClass()); } } private enum ToEnumTypeFunction implements Function<Enum<?>, Class<?>> { INSTANCE; public Class<?> apply(@Nullable final Enum<?> constant) { return constant != null ? constant.getDeclaringClass() : null; } @Override public String toString() { return Classes.toMethodName(this.getClass()); } } private static <F, T> Function<F, T> cast(final Function<?, ?> function) { // only for stateless internal singletons shared across all types @SuppressWarnings({"unchecked", "rawtypes"}) Function<F, T> result = (Function) function; return result; } public static <A extends Annotation> Function<A, Class<? extends A>> toAnnotationTypeFunction() { return cast(ToAnnotationTypeFunction.INSTANCE); } public static <T> Function<T, Class<? extends T>> toClassFunction() { return cast(ToClassFunction.INSTANCE); } public static <E extends Enum<E>> Function<E, Class<E>> toEnumTypeFunction() { return cast(ToEnumTypeFunction.INSTANCE); } public static <T> LinkedList<Class<? super T>> collectSuperclasses(final Class<T> type) { LinkedList<Class<? super T>> superclasses = newLinkedList(); Class<? super T> supertype = type; while ((supertype = supertype.getSuperclass()) != null) { superclasses.add(supertype); } return superclasses; } public static LinkedHashSet<Class<?>> collectInterfaces(final Class<?> type) { Set<Class<?>> resolved = newHashSet(); LinkedHashSet<Class<?>> interfaces = newLinkedHashSet(); interfaces.addAll(asList(type.getInterfaces())); resolved.add(type); for (Class<?> supertype: collectSuperclasses(type)) { groupInterfaces(supertype, resolved, interfaces); } return interfaces; } private static void groupInterfaces(final Class<?> type, final Set<Class<?>> resolved, final Set<Class<?>> result) { if (resolved.add(type)) { for (Class<?> supertype: type.getInterfaces()) { groupInterfaces(supertype, resolved, result); } } if (type.isInterface()) { result.add(type); } } }