Skip to content

Instantly share code, notes, and snippets.

@TimvdLippe
Created February 13, 2019 13:14
Show Gist options
  • Save TimvdLippe/1635f0f1606dca14d6c91d43ec30fac3 to your computer and use it in GitHub Desktop.
Save TimvdLippe/1635f0f1606dca14d6c91d43ec30fac3 to your computer and use it in GitHub Desktop.
Internal copy of Whitebox implementation of Powermock.
package com.facebook.litho;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/** Internal copy of Whitebox implementation of Powermock. */
public class Whitebox {
@SuppressWarnings("unchecked")
public static <T> T getInternalState(Object object, String fieldName) {
Field foundField = findFieldInHierarchy(object.getClass(), fieldName);
try {
return (T) foundField.get(object);
} catch (IllegalAccessException e) {
throw new RuntimeException(
"Internal error: Failed to get field in method getInternalState.", e);
}
}
public static void setInternalState(Object object, String fieldName, Object value) {
Field foundField = findFieldInHierarchy(object.getClass(), fieldName);
try {
foundField.set(object, value);
} catch (IllegalAccessException e) {
throw new RuntimeException(
"Internal error: Failed to get field in method getInternalState.", e);
}
}
private static Field findFieldInHierarchy(Class<?> startClass, String fieldName) {
Field foundField = null;
Class<?> currentClass = startClass;
while (currentClass != null) {
final Field[] declaredFields = currentClass.getDeclaredFields();
for (Field field : declaredFields) {
if (field.getName().equals(fieldName)) {
if (foundField != null) {
throw new IllegalArgumentException(
"Two or more fields matching " + fieldName + " in " + startClass + ".");
}
foundField = field;
}
}
if (foundField != null) {
break;
}
currentClass = currentClass.getSuperclass();
}
if (foundField == null) {
throw new IllegalArgumentException(
"No fields matching " + fieldName + " in " + startClass + ".");
}
foundField.setAccessible(true);
return foundField;
}
@SuppressWarnings("unchecked")
public static <T> T invokeMethod(Object object, String methodName, Object... arguments) {
Method foundMethod = findMethodInHierarchy(object.getClass(), methodName);
try {
return (T) foundMethod.invoke(object, arguments);
} catch (Exception e) {
throw new RuntimeException("Internal error: Failed to invoked method.", e);
}
}
@SuppressWarnings("unchecked")
public static <T> T invokeMethod(Class<?> clazz, String methodName, Object... arguments) {
Method foundMethod = findMethodInHierarchy(clazz, methodName);
try {
return (T) foundMethod.invoke(clazz, arguments);
} catch (Exception e) {
throw new RuntimeException("Internal error: Failed to invoked method.", e);
}
}
private static Method findMethodInHierarchy(Class<?> startClass, String methodName) {
Method foundMethod = null;
Class<?> currentClass = startClass;
while (currentClass != null) {
final Method[] declaredMethods = currentClass.getDeclaredMethods();
for (Method method : declaredMethods) {
if (method.getName().equals(methodName)) {
if (foundMethod != null) {
throw new IllegalArgumentException(
"Two or more methods matching " + methodName + " in " + startClass + ".");
}
foundMethod = method;
}
}
if (foundMethod != null) {
break;
}
currentClass = currentClass.getSuperclass();
}
if (foundMethod == null) {
throw new IllegalArgumentException(
"No methods matching " + methodName + " in " + startClass + ".");
}
foundMethod.setAccessible(true);
return foundMethod;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment