1 package org.broadinstitute.hellbender.utils;
2 
3 import org.broadinstitute.barclay.argparser.ClassFinder;
4 import org.broadinstitute.hellbender.exceptions.GATKException;
5 
6 import java.lang.reflect.InvocationTargetException;
7 import java.lang.reflect.Modifier;
8 import java.util.ArrayList;
9 import java.util.List;
10 import java.util.Set;
11 import java.util.stream.Collectors;
12 
13 /**
14  * Utilities for dealing with reflection.
15  */
16 public final class ClassUtils {
ClassUtils()17     private ClassUtils(){}
18 
19     /**
20      * Returns true iff we can make instances of this class.
21      * Note that this will return false if the class does not have any public constructors.
22      */
canMakeInstances(final Class<?> clazz)23     public static boolean canMakeInstances(final Class<?> clazz) {
24         return clazz != null &&
25                 !clazz.isPrimitive()  &&
26                 !clazz.isSynthetic()  &&
27                 !clazz.isInterface()  &&
28                 !clazz.isLocalClass() &&
29                 !Modifier.isPrivate(clazz.getModifiers()) &&
30                 !Modifier.isAbstract(clazz.getModifiers()) &&
31                 clazz.getConstructors().length != 0;
32     }
33 
34     /**
35      * Finds and creates objects of all concrete subclasses of the given class in the package.
36      * The public no-arg constructor is called to create the objects.
37      *
38      * GATKException is thrown if creation of any object fails.
39      * @param clazz class to be instantiated
40      * @param pack package in which the class will be searched for
41      */
42     @SuppressWarnings("unchecked")
makeInstancesOfSubclasses(final Class<? extends T> clazz, final Package pack)43     public static <T> List<T> makeInstancesOfSubclasses(final Class<? extends T> clazz, final Package pack){
44         Utils.nonNull(clazz, "class");
45         Utils.nonNull(pack, "package");
46         final ClassFinder finder = new ClassFinder();
47         finder.find(pack.getName(), clazz);
48         final Set<Class<?>> classes = finder.getClasses();
49 
50         final List<T> results = new ArrayList<>(classes.size());
51 
52         for (final Class<?> found: classes){
53             final T instance = (T) makeInstanceOf(found);
54             if (instance != null) {
55                 results.add(instance);
56             }
57         }
58         return results;
59     }
60 
61     /**
62      * Create objects of a concrete class.
63      *
64      * The public no-arg constructor is called to create the objects.
65      *
66      * @param clazz class to be instantiated
67      * @return new object or {@code null} if cannot be instantiated.
68      */
makeInstanceOf(final Class<T> clazz)69     public static <T> T makeInstanceOf(final Class<T> clazz) {
70         if (canMakeInstances(clazz)) {
71             try {
72                 return clazz.getDeclaredConstructor().newInstance();
73             } catch (final InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
74                 throw new GATKException("Problem making an instance of " + clazz + " Do check that the class has a non-arg constructor", e);
75             }
76         }
77         return null;
78     }
79 
80     /**
81      * Finds sub-interfaces of the given interface (in the same package) and returns their simple names.
82      */
knownSubInterfaceSimpleNames(final Class<?> iface)83     public static List<String> knownSubInterfaceSimpleNames(final Class<?> iface) {
84         Utils.nonNull(iface);
85         Utils.validateArg(iface.isInterface(), iface + " is not an interface");
86         return knownSubInterfaces(iface).stream().map(c ->c.getSimpleName()).collect(Collectors.toList());
87     }
88 
89     /**
90      * Finds all subinterfaces of the given interface (in the same package).
91      */
knownSubInterfaces(final Class<?> iface)92     public static Set<Class<?>> knownSubInterfaces(final Class<?> iface) {
93         final ClassFinder finder = new ClassFinder();
94         finder.find(iface.getPackage().getName(), iface);
95         return finder.getClasses().stream().filter(cl -> !cl.equals(iface) && cl.isInterface()).collect(Collectors.toSet());
96     }
97 
98     /**
99      * Gets a list of classes that are either the same as, or a subclass/subinterface of a parent target class.
100      * @param targetClass Parent {@link Class} for which to check for inheritance.
101      * @param classesToSearch Classes to check for inheritance against {@code targetClass}.
102      * @return {@link List} of classes from {@code classesToSearch} that inherit from {@code targetClass}.
103      */
getClassesOfType(final Class<?> targetClass, final List<Class<?>> classesToSearch)104     public static List<Class<?>> getClassesOfType(final Class<?> targetClass, final List<Class<?>> classesToSearch) {
105 
106         final List<Class<?>> classList = new ArrayList<>();
107 
108         for ( final Class<?> clazz : classesToSearch ) {
109             if ( targetClass.isAssignableFrom(clazz) ) {
110                 classList.add( clazz );
111             }
112         }
113 
114         return classList;
115     }
116 }
117