package net.sf.openrocket.util;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import net.sf.openrocket.rocketcomponent.RocketComponent;
public class Reflection {
/**
* Simple wrapper class that converts the Method.invoke() exceptions into suitable
* RuntimeExceptions.
*
* @author Sampo Niskanen <sampo.niskanen@iki.fi>
*/
public static class Method {
private final java.lang.reflect.Method method;
public Method(java.lang.reflect.Method m) {
if (m == null) {
throw new IllegalArgumentException("method is null");
}
method = m;
}
/**
* Same as Method.invoke(), but the possible exceptions are wrapped into
* RuntimeExceptions.
*/
public Object invoke(Object obj, Object... args) {
try {
return method.invoke(obj, args);
} catch (IllegalArgumentException e) {
throw new BugException("Error while invoking method '" + method + "'. " +
"Please report this as a bug.", e);
} catch (IllegalAccessException e) {
throw new BugException("Error while invoking method '" + method + "'. " +
"Please report this as a bug.", e);
} catch (InvocationTargetException e) {
throw Reflection.handleWrappedException(e);
}
}
/**
* Invoke static method. Equivalent to invoke(null, args...).
*/
public Object invokeStatic(Object... args) {
return invoke(null, args);
}
/**
* Same as Method.toString().
*/
@Override
public String toString() {
return method.toString();
}
}
/**
* Handles an InvocationTargetException gracefully. If the cause is an unchecked
* exception it is thrown, otherwise it is encapsulated in a BugException.
* <p>
* This method has a return type of Error in order to allow writing code like:
* <pre>throw Reflection.handleInvocationTargetException(e)</pre>
* This allows the compiler verifying that the call will never succeed correctly
* and ending that branch of execution.
*
* @param e the InvocationTargetException that occurred (not null).
* @return never returns normally.
*/
public static Error handleWrappedException(Exception e) {
Throwable cause = e.getCause();
if (cause == null) {
throw new BugException("wrapped exception without cause", e);
}
if (cause instanceof RuntimeException) {
throw (RuntimeException) cause;
}
if (cause instanceof Error) {
throw (Error) cause;
}
throw new BugException("wrapped exception occurred", cause);
}
/**
* Find a method from a class.
* Throws an exception if method not found.
*/
public static Reflection.Method findMethod(Class<?> c, String method, Class<?>... params) {
java.lang.reflect.Method m;
try {
m = c.getMethod(method, params);
return new Reflection.Method(m);
} catch (NoSuchMethodException e) {
throw new BugException("Could not find method " + method + "(" + Arrays.toString(params) + ") from class " + c);
}
}
public static Reflection.Method findMethod(String pack, RocketComponent component,
String method, Class<?>... params) {
return findMethod(pack, component.getClass(), "", method, params);
}
public static Reflection.Method findMethod(String pack, RocketComponent component,
String suffix, String method, Class<?>... params) {
return findMethod(pack, component.getClass(), suffix, method, params);
}
public static Reflection.Method findMethod(String pack,
Class<? extends RocketComponent> componentClass,
String suffix, String method, Class<?>... params) {
Class<?> currentclass;
String name;
currentclass = componentClass;
while ((currentclass != null) && (currentclass != Object.class)) {
name = currentclass.getCanonicalName();
if (name.lastIndexOf('.') >= 0)
name = name.substring(name.lastIndexOf(".") + 1);
name = pack + "." + name + suffix;
try {
Class<?> c = Class.forName(name);
java.lang.reflect.Method m = c.getMethod(method, params);
return new Reflection.Method(m);
} catch (ClassNotFoundException ignore) {
} catch (NoSuchMethodException ignore) {
}
currentclass = currentclass.getSuperclass();
}
return null;
}
public static Object construct(String pack, RocketComponent component, String suffix,
Object... params) {
Class<?> currentclass;
String name;
currentclass = component.getClass();
while ((currentclass != null) && (currentclass != Object.class)) {
name = currentclass.getCanonicalName();
if (name.lastIndexOf('.') >= 0)
name = name.substring(name.lastIndexOf(".") + 1);
name = pack + "." + name + suffix;
try {
Class<?> c = Class.forName(name);
Class<?>[] paramClasses = new Class<?>[params.length];
for (int i = 0; i < params.length; i++) {
paramClasses[i] = params[i].getClass();
}
// Constructors must be searched manually. Why?!
main: for (Constructor<?> constructor : c.getConstructors()) {
Class<?>[] parameterTypes = constructor.getParameterTypes();
if (params.length != parameterTypes.length)
continue;
for (int i = 0; i < params.length; i++) {
if (!parameterTypes[i].isInstance(params[i]))
continue main;
}
// Matching constructor found
return constructor.newInstance(params);
}
} catch (ClassNotFoundException ignore) {
} catch (IllegalArgumentException e) {
throw new BugException("Construction of " + name + " failed", e);
} catch (InstantiationException e) {
throw new BugException("Construction of " + name + " failed", e);
} catch (IllegalAccessException e) {
throw new BugException("Construction of " + name + " failed", e);
} catch (InvocationTargetException e) {
throw Reflection.handleWrappedException(e);
}
currentclass = currentclass.getSuperclass();
}
throw new BugException("Suitable constructor for component " + component +
" not found");
}
}