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 * Find a method from the rocket component classes.
94 * Throws an exception if method not found.
96 public static Reflection.Method findMethod(
97 Class<? extends RocketComponent> componentClass,
98 String method, Class<?>... params) {
99 Reflection.Method m = findMethod(ROCKETCOMPONENT_PACKAGE, componentClass,
102 throw new BugException("Could not find method for componentClass="
103 + componentClass + " method=" + method);
110 public static Reflection.Method findMethod(String pack, RocketComponent component,
111 String method, Class<?>... params) {
112 return findMethod(pack, component.getClass(), "", method, params);
116 public static Reflection.Method findMethod(String pack, RocketComponent component,
117 String suffix, String method, Class<?>... params) {
118 return findMethod(pack, component.getClass(), suffix, method, params);
122 public static Reflection.Method findMethod(String pack,
123 Class<? extends RocketComponent> componentClass,
124 String suffix, String method, Class<?>... params) {
125 Class<?> currentclass;
128 currentclass = componentClass;
129 while ((currentclass != null) && (currentclass != Object.class)) {
130 name = currentclass.getCanonicalName();
131 if (name.lastIndexOf('.') >= 0)
132 name = name.substring(name.lastIndexOf(".") + 1);
133 name = pack + "." + name + suffix;
136 Class<?> c = Class.forName(name);
137 java.lang.reflect.Method m = c.getMethod(method, params);
138 return new Reflection.Method(m);
139 } catch (ClassNotFoundException ignore) {
140 } catch (NoSuchMethodException ignore) {
143 currentclass = currentclass.getSuperclass();
149 public static Object construct(String pack, RocketComponent component, String suffix,
152 Class<?> currentclass;
155 currentclass = component.getClass();
156 while ((currentclass != null) && (currentclass != Object.class)) {
157 name = currentclass.getCanonicalName();
158 if (name.lastIndexOf('.') >= 0)
159 name = name.substring(name.lastIndexOf(".") + 1);
160 name = pack + "." + name + suffix;
163 Class<?> c = Class.forName(name);
164 Class<?>[] paramClasses = new Class<?>[params.length];
165 for (int i = 0; i < params.length; i++) {
166 paramClasses[i] = params[i].getClass();
169 // Constructors must be searched manually. Why?!
170 main: for (Constructor<?> constructor : c.getConstructors()) {
171 Class<?>[] parameterTypes = constructor.getParameterTypes();
172 if (params.length != parameterTypes.length)
174 for (int i = 0; i < params.length; i++) {
175 if (!parameterTypes[i].isInstance(params[i]))
178 // Matching constructor found
179 return constructor.newInstance(params);
181 } catch (ClassNotFoundException ignore) {
182 } catch (IllegalArgumentException e) {
183 throw new BugException("Construction of " + name + " failed", e);
184 } catch (InstantiationException e) {
185 throw new BugException("Construction of " + name + " failed", e);
186 } catch (IllegalAccessException e) {
187 throw new BugException("Construction of " + name + " failed", e);
188 } catch (InvocationTargetException e) {
189 throw Reflection.handleWrappedException(e);
192 currentclass = currentclass.getSuperclass();
194 throw new BugException("Suitable constructor for component " + component +