package de.hilling.junit.cdi.util; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import org.junit.runner.RunWith; import de.hilling.junit.cdi.CdiUnitRunner; import de.hilling.junit.cdi.annotations.BypassTestInterceptor; public final class ReflectionsUtils { private ReflectionsUtils() { } private static final String[] SYSTEM_PACKAGES = { "java", "javax", "com.sun", "org.apache.deltaspike", "org.jboss" }; public static List<Field> getAllFields(Class<?> clazz) { List<Field> result = new ArrayList<>(); result.addAll(Arrays.asList(clazz.getDeclaredFields())); Class<?> superClass = clazz.getSuperclass(); if (!superClass.equals(Object.class)) { result.addAll(getAllFields(superClass)); } return result; } public static Class<? extends Object> getOriginalClass( Class<? extends Object> clazz) { String canonicalName = clazz.getCanonicalName(); if (canonicalName.contains("$")) { try { if (clazz.getPackage() == null) return Class.forName(canonicalName.substring(canonicalName.lastIndexOf(".") + 1, canonicalName.indexOf("$"))); return Class.forName(canonicalName.substring(0, canonicalName.indexOf("$"))); } catch (ClassNotFoundException e) { throw new RuntimeException("unable to find original class", e); } } else { return clazz; } } /** * Determine is the given class is a junit cdi test. * <p> * This is done by checking for the annotation {@link RunWith} annotation. * </p> * @param javaClass class to verify * @param <X> type of class * @return true if it is a junit test. */ public static <X> boolean isTestClass(Class<X> javaClass) { if (javaClass.isAnnotationPresent(RunWith.class)) { RunWith annotation = javaClass.getAnnotation(RunWith.class); return annotation.value().isAssignableFrom(CdiUnitRunner.class); } else { return false; } } /** * Determine if a proxy should be created for the given class. * <p>The following classes will be excluded:</p> * <ul> * <li>System classes, including those from weld and deltaspike.</li> * <li>Classes that are not proxyable.</li> * </ul> * @param javaClass class to verify * @param <X> type of class * @return true if a cdi proxy should be created. */ public static <X> boolean shouldProxyCdiType(Class<X> javaClass) { return !isSystemClass(javaClass) && isProxyable(javaClass); } public static <X> boolean isSystemClass(Class<X> javaClass) { if (javaClass.isAnnotationPresent(BypassTestInterceptor.class)) { return true; } if (javaClass.getPackage() == null) { return false; } String packageName = javaClass.getPackage().getName(); for(String packagePrefix: SYSTEM_PACKAGES) { if(packageName.startsWith(packagePrefix)) { return true; } } return false; } public static <X> boolean isProxyable(Class<X> javaClass) { if (javaClass.isAnonymousClass()) { return false; } if (javaClass.isEnum()) { return false; } if (javaClass.isPrimitive()) { return false; } if (Modifier.isFinal(javaClass.getModifiers())) { return false; } if (!hasPublicConstructor(javaClass)) { return false; } if (hasFinalMethods(javaClass)) { return false; } return !javaClass.isEnum(); } public static <X> boolean hasFinalMethods(Class<X> javaClass) { Method[] methods = javaClass.getMethods(); for (Method method : methods) { if (method.getDeclaringClass().getPackage() != null && method.getDeclaringClass().getPackage() .getName().startsWith("java.lang")) { continue; } if (Modifier.isFinal(method.getModifiers())) { return true; } } return false; } public static <X> boolean hasPublicConstructor(Class<X> javaClass) { try { Constructor<X> constructor = javaClass.getConstructor(); if (!Modifier.isPublic(constructor.getModifiers())) { return false; } } catch (NoSuchMethodException e) { return false; } return true; } }