package reflection.api; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Modifier; import java.util.HashSet; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; public class ReflectionInvestigator implements Investigator { private Object subjectInstance; private Class classInfo; public ReflectionInvestigator() {} @Override public void load(Object anInstanceOfSomething) { subjectInstance = anInstanceOfSomething; classInfo = subjectInstance.getClass(); } @Override public int getTotalNumberOfMethods() { return classInfo.getDeclaredMethods().length; } @Override public int getTotalNumberOfConstructors() { return classInfo.getConstructors().length; } @Override public int getTotalNumberOfFields() { return classInfo.getDeclaredFields().length; } @Override public Set getAllImplementedInterfaces() { return Stream.of(classInfo.getInterfaces()) .map(info -> info.getSimpleName()) .collect(Collectors.toSet()); } @Override public int getCountOfConstantFields() { return Stream.of(classInfo.getDeclaredFields()) .filter(f -> Modifier.isFinal(f.getModifiers())) .toArray() .length; } @Override public int getCountOfStaticMethods() { return Stream.of(classInfo.getMethods()) .filter(m -> Modifier.isStatic(m.getModifiers())) .toArray() .length; } @Override public boolean isExtending() { return classInfo.getSuperclass() != Object.class; } @Override public String getParentClassSimpleName() { return classInfo.getSuperclass().getSimpleName(); } @Override public boolean isParentClassAbstract() { return Modifier.isAbstract(classInfo.getSuperclass().getModifiers()); } @Override public Set getNamesOfAllFieldsIncludingInheritanceChain() { var fields = new HashSet(); var cursor = classInfo; while (cursor != null) { fields.addAll( Stream.of(classInfo.getDeclaredFields()) .map(f -> f.getName()) .collect(Collectors.toSet())); cursor = cursor.getSuperclass(); } return fields; } @Override public int invokeMethodThatReturnsInt(String methodName, Object... args) { try { return (int) classInfo.getMethod(methodName).invoke(subjectInstance, args); } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { return 0; } } @Override public Object createInstance(int numberOfArgs, Object... args) { var ctors = classInfo.getDeclaredConstructors(); for (var ctor : ctors) { if (ctor.getGenericParameterTypes().length == numberOfArgs) { try { return ctor.newInstance(args); } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { break; } } } return null; } @Override public Object elevateMethodAndInvoke(String name, Class[] parametersTypes, Object... args) { try { var method = classInfo.getDeclaredMethod(name, parametersTypes); method.setAccessible(true); return method.invoke(subjectInstance, args); } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { return null; } } @Override public String getInheritanceChain(String delimiter) { var nameStack = new HashSet(); nameStack.add(classInfo.getSimpleName()); var cursor = classInfo; while (cursor != null) { nameStack.add(cursor.getSimpleName()); cursor = cursor.getSuperclass(); } return String.join(" >> ", nameStack); } }