1 package net.sf.openrocket.util;
3 import java.lang.reflect.Constructor;
4 import java.lang.reflect.InvocationTargetException;
6 import net.sf.openrocket.rocketcomponent.RocketComponent;
9 public class Reflection {
11 private static final String ROCKETCOMPONENT_PACKAGE = "net.sf.openrocket.rocketcomponent";
14 * Simple wrapper class that converts the Method.invoke() exceptions into suitable
17 * @author Sampo Niskanen <sampo.niskanen@iki.fi>
19 public static class Method {
20 private final java.lang.reflect.Method method;
22 public Method(java.lang.reflect.Method m) {
24 throw new IllegalArgumentException("method is null");
30 * Same as Method.invoke(), but the possible exceptions are wrapped into
33 public Object invoke(Object obj, Object... args) {
35 return method.invoke(obj, args);
36 } catch (IllegalArgumentException e) {
37 throw new BugException("Error while invoking method '" + method + "'. " +
38 "Please report this as a bug.", e);
39 } catch (IllegalAccessException e) {
40 throw new BugException("Error while invoking method '" + method + "'. " +
41 "Please report this as a bug.", e);
42 } catch (InvocationTargetException e) {
43 throw Reflection.handleWrappedException(e);
48 * Invoke static method. Equivalent to invoke(null, args...).
50 public Object invokeStatic(Object... args) {
51 return invoke(null, args);
55 * Same as Method.toString().
58 public String toString() {
59 return method.toString();
65 * Handles an InvocationTargetException gracefully. If the cause is an unchecked
66 * exception it is thrown, otherwise it is encapsulated in a BugException.
68 * This method has a return type of Error in order to allow writing code like:
69 * <pre>throw Reflection.handleInvocationTargetException(e)</pre>
70 * This allows the compiler verifying that the call will never succeed correctly
71 * and ending that branch of execution.
73 * @param e the InvocationTargetException that occurred (not null).
74 * @return never returns normally.
76 public static Error handleWrappedException(Exception e) {
77 Throwable cause = e.getCause();
79 throw new BugException("wrapped exception without cause", e);
81 if (cause instanceof RuntimeException) {
82 throw (RuntimeException) cause;
84 if (cause instanceof Error) {
87 throw new BugException("wrapped exception occurred", cause);
93 * Throws an exception if method not found.
95 public static Reflection.Method findMethodStatic(
96 Class<? extends RocketComponent> componentClass,
97 String method, Class<?>... params) {
98 Reflection.Method m = findMethod(ROCKETCOMPONENT_PACKAGE, componentClass,
101 throw new BugException("Could not find method for componentClass="
102 + componentClass + " method=" + method);
109 public static Reflection.Method findMethod(String pack, RocketComponent component,
110 String method, Class<?>... params) {
111 return findMethod(pack, component.getClass(), "", method, params);
115 public static Reflection.Method findMethod(String pack, RocketComponent component,
116 String suffix, String method, Class<?>... params) {
117 return findMethod(pack, component.getClass(), suffix, method, params);
121 public static Reflection.Method findMethod(String pack,
122 Class<? extends RocketComponent> componentClass,
123 String suffix, String method, Class<?>... params) {
124 Class<?> currentclass;
127 currentclass = componentClass;
128 while ((currentclass != null) && (currentclass != Object.class)) {
129 name = currentclass.getCanonicalName();
130 if (name.lastIndexOf('.') >= 0)
131 name = name.substring(name.lastIndexOf(".") + 1);
132 name = pack + "." + name + suffix;
135 Class<?> c = Class.forName(name);
136 java.lang.reflect.Method m = c.getMethod(method, params);
137 return new Reflection.Method(m);
138 } catch (ClassNotFoundException ignore) {
139 } catch (NoSuchMethodException ignore) {
142 currentclass = currentclass.getSuperclass();
148 public static Object construct(String pack, RocketComponent component, String suffix,
151 Class<?> currentclass;
154 currentclass = component.getClass();
155 while ((currentclass != null) && (currentclass != Object.class)) {
156 name = currentclass.getCanonicalName();
157 if (name.lastIndexOf('.') >= 0)
158 name = name.substring(name.lastIndexOf(".") + 1);
159 name = pack + "." + name + suffix;
162 Class<?> c = Class.forName(name);
163 Class<?>[] paramClasses = new Class<?>[params.length];
164 for (int i = 0; i < params.length; i++) {
165 paramClasses[i] = params[i].getClass();
168 // Constructors must be searched manually. Why?!
169 main: for (Constructor<?> constructor : c.getConstructors()) {
170 Class<?>[] parameterTypes = constructor.getParameterTypes();
171 if (params.length != parameterTypes.length)
173 for (int i = 0; i < params.length; i++) {
174 if (!parameterTypes[i].isInstance(params[i]))
177 // Matching constructor found
178 return constructor.newInstance(params);
180 } catch (ClassNotFoundException ignore) {
181 } catch (IllegalArgumentException e) {
182 throw new BugException("Construction of " + name + " failed", e);
183 } catch (InstantiationException e) {
184 throw new BugException("Construction of " + name + " failed", e);
185 } catch (IllegalAccessException e) {
186 throw new BugException("Construction of " + name + " failed", e);
187 } catch (InvocationTargetException e) {
188 throw Reflection.handleWrappedException(e);
191 currentclass = currentclass.getSuperclass();
193 throw new BugException("Suitable constructor for component " + component +