package gov.nasa.jpl.mbee.mdk.util;
import java.lang.reflect.*;
import java.util.*;
public class ClassUtils {
public static Class<?> classForPrimitive(Class<?> primClass) {
return getPrimToNonPrim().get(primClass);
}
private static Map<Class<?>, Class<?>> primToNonPrim;
public static Map<Class<?>, Class<?>> getPrimToNonPrim() {
if (primToNonPrim == null) {
initializePrimToNonPrim();
}
return primToNonPrim;
}
private static Map<Class<?>, Class<?>> initializePrimToNonPrim() {
primToNonPrim = new HashMap<>(9);
primToNonPrim.put(boolean.class, Boolean.class);
primToNonPrim.put(byte.class, Byte.class);
primToNonPrim.put(char.class, Character.class);
primToNonPrim.put(short.class, Short.class);
primToNonPrim.put(int.class, Integer.class);
primToNonPrim.put(long.class, Long.class);
primToNonPrim.put(float.class, Float.class);
primToNonPrim.put(double.class, Double.class);
primToNonPrim.put(void.class, Void.class);
return primToNonPrim;
}
public static Pair<Boolean, Object> runMethod(boolean suppressErrors, Object o, Method method, Object... args) {
Pair<Boolean, Object> p = new Pair<>(false, null);
List<Throwable> errors = new ArrayList<>();
try {
p = runMethod(o, method, args);
} catch (IllegalArgumentException | IllegalAccessException | InvocationTargetException e) {
if (!suppressErrors) {
errors.add(e);
}
}
if (!p.getKey() && isStatic(method) && o != null) {
List<Object> l = Utils2.newList(o);
l.addAll(Arrays.asList(args));
p = runMethod(true, (Object) null, method, l.toArray());
if (!p.getKey() && l.size() > 1) {
p = runMethod(true, (Object) null, method, o);
}
}
if (!suppressErrors && !p.getKey()) {
Debug.error(false, "runMethod( " + o + ", " + method + ", " + Utils2.toString(args, true) + " ) failed!");
}
for (Throwable e : errors) {
e.printStackTrace();
}
return p;
}
public static boolean isStatic(Member method) {
if (method == null) {
return false;
}
return (Modifier.isStatic(method.getModifiers()));
}
/**
* Invoke the method from the given object with the given arguments.
*
* @param o
* @param m
* @param args
* @return in a Pair whether the invocation was successful and the return
* value (or null)
* @throws IllegalArgumentException
* @throws IllegalAccessException
* @throws InvocationTargetException
*/
public static Pair<Boolean, Object> runMethod(Object o, Method m, Object... args) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
return new Pair<>(m != null, m != null ? m.invoke(o, args) : null);
}
/**
* Get the Field of the Class of the object with the given fieldName using
* reflection.
*
* @param o the object whose field is sought
* @param fieldName
* @return the Field of the Class
*/
public static Field getField(Object o, String fieldName) throws IllegalArgumentException {
if (o == null || Utils2.isNullOrEmpty(fieldName)) {
return null;
}
try {
return o.getClass().getField(fieldName);
} catch (NoSuchFieldException | SecurityException ignored) {
}
return null;
}
/**
* @param type
* @return whether the input type is a number class or a number primitive.
*/
public static boolean isNumber(Class<?> type) {
if (type == null) {
return false;
}
Class<?> forPrim = classForPrimitive(type);
if (forPrim != null) {
type = forPrim;
}
return (Number.class.isAssignableFrom(type));
}
/**
* @param cls
* @param methodName
* @return all public methods of {@code cls} (or inherited by {@code cls})
* that have the simple name, {@code methodName}.
*/
public static Method[] getMethodsForName(Class<?> cls, String methodName) {
List<Method> methods = new ArrayList<>();
for (Method m : cls.getMethods()) {
if (m.getName().equals(methodName)) {
methods.add(m);
}
}
Method[] mArr = new Method[methods.size()];
boolean succ = Utils2.toArrayOfType(methods, mArr, Method.class);
if (!succ) {
Debug.error("Error! Cast to Method[] failed for getMethodsForName(" + cls + ", " + methodName
+ ")");
}
return mArr;
}
/**
* Try to convert an object into one of the specified class.
*
* @param o the object to convert into type cls
* @param cls the {@link Class} of the object to return
* @return an object of the type specified or null if the conversion was
* unsuccessful.
*/
@SuppressWarnings("unchecked")
public static <T> Pair<Boolean, T> coerce(Object o, Class<T> cls) {
if (o == null) {
return new Pair<>(false, null);
}
Object v = evaluate(o, cls);
Boolean succ = null;
T t = null;
if (v != null) {
succ = true;
try {
if (cls == null) {
t = (T) v;
}
else {
t = cls.cast(v);
}
} catch (ClassCastException e) {
succ = false;
}
if (t == null) {
succ = false;
}
}
return new Pair<>(succ, t);
}
/**
* Evaluate/dig or wrap the object of the given type cls from the object o,
* which may be a Parameter or an Expression.
*
* @param object the object to evaluate
* @param cls the type of the object to find
* @return o if o is of type cls, an object of type cls that is an
* evaluation of o, or null otherwise.
*/
@SuppressWarnings("unchecked")
public static <TT> TT evaluate(Object object, Class<TT> cls) throws ClassCastException {
if (object == null) {
return null;
}
// Check if object is already what we want.
if (cls != null && cls.isInstance(object) || cls == object.getClass()) {
return (TT) object;
}
if (cls != null && ClassUtils.isNumber(cls) && ClassUtils.isNumber(object.getClass())) {
try {
Number n = (Number) object;
Class<?> c = ClassUtils.classForPrimitive(cls);
if (c == null) {
c = cls;
}
// TODO -- instead of returning here, assign to object and reuse
// try/catch below
if (c == Long.class) {
return (TT) (Long) n.longValue();
}
if (c == Short.class) {
return (TT) (Short) n.shortValue();
}
if (c == Double.class) {
return (TT) (Double) n.doubleValue();
}
if (c == Integer.class) {
return (TT) (Integer) n.intValue();
}
if (c == Float.class) {
return (TT) (Float) n.floatValue();
}
} catch (Exception e) {
// ignore
}
}
TT r;
try {
r = (TT) object;
} catch (ClassCastException cce) {
Debug.errln("Warning! No evaluation of " + object + " with type " + cls.getName() + "!");
throw cce;
}
if (cls != null && cls.isInstance(r) || cls == r.getClass()) {
return r;
}
return null;
}
/**
* @param o
* @return a collection of o's Class, superclasses, and interfaces
*/
public static List<Class<?>> getAllClasses(Object o) {
Class<?> cls = (Class<?>) (o instanceof Class ? o : o.getClass());
HashSet<Class<?>> set = new HashSet<>();
List<Class<?>> classes = new ArrayList<>();
List<Class<?>> queue = new ArrayList<>();
queue.add(cls);
while (!queue.isEmpty()) {
Class<?> c = queue.get(0);
queue.remove(0);
if (set.contains(c)) {
continue;
}
Class<?> parent = cls.getSuperclass();
if (parent != null && !set.contains(parent)) {
queue.add(parent);
}
queue.addAll(Arrays.asList(cls.getInterfaces()));
classes.add(0, c);
set.add(c);
}
return classes;
}
}