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