/*
* Copyright (C) 2015 Red Hat, Inc. and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jboss.errai.reflections;
import com.google.common.base.Predicates;
import com.google.common.collect.Collections2;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.jboss.errai.reflections.util.ClasspathHelper;
import java.lang.String;
import java.lang.reflect.AnnotatedElement;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.*;
//todo add some ReflectionUtils stuff here
/** convenient reflection methods */
public abstract class ReflectionUtils {
//primitive parallel arrays
public final static List<String> primitiveNames = Lists.newArrayList("boolean", "char", "byte", "short", "int", "long", "float", "double", "void");
@SuppressWarnings({"unchecked"}) public final static List<Class> primitiveTypes = Lists.<Class>newArrayList(boolean.class, char.class, byte.class, short.class, int.class, long.class, float.class, double.class, void.class);
public final static List<String> primitiveDescriptors = Lists.newArrayList("Z", "C", "B", "S", "I", "J", "F", "D", "V");
public static <T> Collection<? extends Class<?>> getAllSuperTypes(final Class<T> type) {
Collection<Class<?>> result = Lists.newArrayList();
Class<? super T> superclass = type.getSuperclass();
Class<?>[] interfaces = type.getInterfaces();
Collections.addAll(result, interfaces);
result.add(superclass);
result = Collections2.filter(result, Predicates.notNull());
Collection<Class<?>> subResult = Lists.newArrayList();
for (Class<?> aClass1 : result) {
Collection<? extends Class<?>> classes = getAllSuperTypes(aClass1);
subResult.addAll(classes);
}
result.addAll(subResult);
return result;
}
/** return all super types of a given annotated element annotated with a given annotation up in hierarchy, including the given type */
public static List<AnnotatedElement> getAllSuperTypesAnnotatedWith(final AnnotatedElement annotatedElement, final Annotation annotation) {
final List<AnnotatedElement> annotated = Lists.newArrayList();
if (annotatedElement != null) {
if (annotatedElement.isAnnotationPresent(annotation.annotationType())) {
annotated.add(annotatedElement);
}
if (annotatedElement instanceof Class<?>) {
List<AnnotatedElement> subResult = Lists.newArrayList();
Class<?> aClass = (Class<?>) annotatedElement;
subResult.addAll(getAllSuperTypesAnnotatedWith(aClass.getSuperclass(), annotation));
for (AnnotatedElement anInterface : aClass.getInterfaces()) {
subResult.addAll(getAllSuperTypesAnnotatedWith(anInterface, annotation));
}
annotated.addAll(subResult);
}
}
return annotated;
}
/**
* checks for annotation member values matching, based on equality of members
*/
public static boolean areAnnotationMembersMatching(Annotation annotation1, Annotation annotation2) {
if (annotation2 != null && annotation1.annotationType() == annotation2.annotationType()) {
for (Method method : annotation1.annotationType().getDeclaredMethods()) {
try {
if (!method.invoke(annotation1).equals(method.invoke(annotation2))) {
return false;
}
} catch (Exception e) {
throw new ReflectionsException(String.format("could not invoke method %s on annotation %s", method.getName(), annotation1.annotationType()), e);
}
}
return true;
}
return false;
}
/**
* checks for annotation member values matching on an annotated element or it's first annotated super type, based on equality of members
*/
protected static boolean areAnnotationMembersMatching(final Annotation annotation1, final AnnotatedElement annotatedElement) {
List<AnnotatedElement> elementList = ReflectionUtils.getAllSuperTypesAnnotatedWith(annotatedElement, annotation1);
if (!elementList.isEmpty()) {
AnnotatedElement element = elementList.get(0);
Annotation annotation2 = element.getAnnotation(annotation1.annotationType());
return areAnnotationMembersMatching(annotation1, annotation2);
}
return false;
}
/**
* returns a subset of given annotatedWith, where annotation member values matches the given annotation
*/
protected static <T extends AnnotatedElement> Set<T> getMatchingAnnotations(final Set<T> annotatedElements, final Annotation annotation) {
Set<T> result = Sets.newHashSet();
for (T annotatedElement : annotatedElements) {
if (areAnnotationMembersMatching(annotation, annotatedElement)) {
result.add(annotatedElement);
}
}
return result;
}
/** tries to resolve a java type name to a Class
* <p>if optional {@link ClassLoader}s are not specified, then both {@link org.jboss.errai.reflections.util.ClasspathHelper#getContextClassLoader()} and {@link org.jboss.errai.reflections.util.ClasspathHelper#getStaticClassLoader()} are used
* */
public static Class<?> forName(String typeName, ClassLoader... classLoaders) {
if (primitiveNames.contains(typeName)) {
return primitiveTypes.get(primitiveNames.indexOf(typeName));
} else {
String type;
if (typeName.contains("[")) {
int i = typeName.indexOf("[");
type = typeName.substring(0, i);
String array = typeName.substring(i).replace("]", "");
if (primitiveNames.contains(type)) {
type = primitiveDescriptors.get(primitiveNames.indexOf(type));
} else {
type = "L" + type + ";";
}
type = array + type;
} else {
type = typeName;
}
for (ClassLoader classLoader : ClasspathHelper.classLoaders(classLoaders)) {
try { return Class.forName(type, false, classLoader); }
catch (ClassNotFoundException e) { /*continue*/ }
}
throw new IllegalArgumentException("Unable to load class \"" + type + "\"");
}
}
/** try to resolve all given string representation of types to a list of java types */
public static <T> Class<? extends T>[] forNames(final Iterable<String> classes, ClassLoader... classLoaders) {
List<Class<? extends T>> result = new ArrayList<Class<? extends T>>();
for (String className : classes) {
//noinspection unchecked
result.add((Class<? extends T>) forName(className, classLoaders));
}
return result.toArray(new Class[result.size()]);
}
}