提交 edd6df0d authored 作者: Thomas Mueller's avatar Thomas Mueller

Reflection utilities.

上级 a2ea25e0
...@@ -261,9 +261,7 @@ ShutdownHandler { ...@@ -261,9 +261,7 @@ ShutdownHandler {
private boolean createTrayIcon() { private boolean createTrayIcon() {
try { try {
// SystemTray.isSupported(); // SystemTray.isSupported();
Boolean supported = (Boolean) Class.forName("java.awt.SystemTray"). boolean supported = (Boolean) Utils.callStaticMethod("java.awt.SystemTray.isSupported");
getMethod("isSupported").
invoke(null);
if (!supported) { if (!supported) {
return false; return false;
} }
...@@ -285,14 +283,11 @@ ShutdownHandler { ...@@ -285,14 +283,11 @@ ShutdownHandler {
menuConsole.add(itemExit); menuConsole.add(itemExit);
// SystemTray tray = SystemTray.getSystemTray(); // SystemTray tray = SystemTray.getSystemTray();
Object tray = Class.forName("java.awt.SystemTray"). Object tray = Utils.callStaticMethod("java.awt.SystemTray.getSystemTray");
getMethod("getSystemTray").
invoke(null);
// Dimension d = tray.getTrayIconSize(); // Dimension d = tray.getTrayIconSize();
Dimension d = (Dimension) Class.forName("java.awt.SystemTray"). Dimension d = (Dimension) Utils.callMethod(tray, "getTrayIconSize");
getMethod("getTrayIconSize").
invoke(tray);
String iconFile; String iconFile;
if (d.width >= 24 && d.height >= 24) { if (d.width >= 24 && d.height >= 24) {
iconFile = "/org/h2/res/h2-24.png"; iconFile = "/org/h2/res/h2-24.png";
...@@ -302,20 +297,15 @@ ShutdownHandler { ...@@ -302,20 +297,15 @@ ShutdownHandler {
iconFile = "/org/h2/res/h2.png"; iconFile = "/org/h2/res/h2.png";
} }
Image icon = loadImage(iconFile); Image icon = loadImage(iconFile);
// TrayIcon icon = new TrayIcon(image, "H2 Database Engine", menuConsole);
Object ti = Class.forName("java.awt.TrayIcon"). // TrayIcon ti = new TrayIcon(image, "H2 Database Engine", menuConsole);
getConstructor(Image.class, String.class, PopupMenu.class). Object ti = Utils.newInstance("java.awt.TrayIcon", icon, "H2 Database Engine", menuConsole);
newInstance(icon, "H2 Database Engine", menuConsole);
// ti.addMouseListener(this);
// trayIcon.addMouseListener(this); Utils.callMethod(ti, "addMouseListener", this);
ti.getClass().
getMethod("addMouseListener", MouseListener.class). // tray.add(ti);
invoke(ti, this); Utils.callMethod(tray, "add", ti);
// tray.add(icon);
tray.getClass().
getMethod("add", Class.forName("java.awt.TrayIcon")).
invoke(tray, ti);
this.trayIcon = true; this.trayIcon = true;
......
...@@ -12,7 +12,6 @@ import java.io.InputStream; ...@@ -12,7 +12,6 @@ import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.PrintStream; import java.io.PrintStream;
import java.io.StringReader; import java.io.StringReader;
import java.lang.reflect.Method;
import java.sql.Connection; import java.sql.Connection;
import java.sql.DriverManager; import java.sql.DriverManager;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
...@@ -24,13 +23,13 @@ import java.util.ArrayList; ...@@ -24,13 +23,13 @@ import java.util.ArrayList;
import java.util.Properties; import java.util.Properties;
import org.h2.engine.Constants; import org.h2.engine.Constants;
import org.h2.server.web.ConnectionInfo; import org.h2.server.web.ConnectionInfo;
import org.h2.util.ScriptReader;
import org.h2.util.Utils;
import org.h2.util.IOUtils; import org.h2.util.IOUtils;
import org.h2.util.JdbcUtils; import org.h2.util.JdbcUtils;
import org.h2.util.New; import org.h2.util.New;
import org.h2.util.ScriptReader;
import org.h2.util.SortedProperties; import org.h2.util.SortedProperties;
import org.h2.util.Tool; import org.h2.util.Tool;
import org.h2.util.Utils;
/** /**
* Interactive command line tool to access a database using JDBC. * Interactive command line tool to access a database using JDBC.
...@@ -414,11 +413,9 @@ public class Shell extends Tool implements Runnable { ...@@ -414,11 +413,9 @@ public class Shell extends Tool implements Runnable {
private String readPassword() throws IOException { private String readPassword() throws IOException {
try { try {
Method getConsole = System.class.getMethod("console"); Object console = Utils.callStaticMethod("java.lang.System.console");
Object console = getConsole.invoke(null);
Method readPassword = console.getClass().getMethod("readPassword");
print("Password "); print("Password ");
char[] password = (char[]) readPassword.invoke(console); char[] password = (char[]) Utils.callMethod(console, "readPassword");
return password == null ? null : new String(password); return password == null ? null : new String(password);
} catch (Exception e) { } catch (Exception e) {
// ignore, use the default solution // ignore, use the default solution
......
...@@ -64,9 +64,9 @@ public class DbUpgradeNonPageStoreToCurrent { ...@@ -64,9 +64,9 @@ public class DbUpgradeNonPageStoreToCurrent {
oldUrl = oldUrl.replaceAll(";IFEXISTS=FALSE", ""); oldUrl = oldUrl.replaceAll(";IFEXISTS=FALSE", "");
oldUrl += ";IGNORE_UNKNOWN_SETTINGS=TRUE"; oldUrl += ";IGNORE_UNKNOWN_SETTINGS=TRUE";
Object ci = Utils.newInstance("org.h2.upgrade.v1_1.engine.ConnectionInfo", oldUrl, info); Object ci = Utils.newInstance("org.h2.upgrade.v1_1.engine.ConnectionInfo", oldUrl, info);
boolean isRemote = (Boolean) Utils.callMethod("isRemote", ci); boolean isRemote = (Boolean) Utils.callMethod(ci, "isRemote");
boolean isPersistent = (Boolean) Utils.callMethod("isPersistent", ci); boolean isPersistent = (Boolean) Utils.callMethod(ci, "isPersistent");
String dbName = (String) Utils.callMethod("getName", ci); String dbName = (String) Utils.callMethod(ci, "getName");
// remove stackable file systems // remove stackable file systems
int colon = dbName.indexOf(':'); int colon = dbName.indexOf(':');
while (colon != -1) { while (colon != -1) {
......
...@@ -13,9 +13,9 @@ import java.io.InputStream; ...@@ -13,9 +13,9 @@ import java.io.InputStream;
import java.io.ObjectInputStream; import java.io.ObjectInputStream;
import java.io.ObjectOutputStream; import java.io.ObjectOutputStream;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
...@@ -548,106 +548,95 @@ public class Utils { ...@@ -548,106 +548,95 @@ public class Utils {
} }
/** /**
* Calls a static method via reflection. The order in which the method is * Calls a static method via reflection. This will try to use the method
* searched: * where the most parameter classes match exactly (this algorithm is simpler
* - With object arguments, eg. doSomething(Integer) * than the one in the Java specification, but works well for most cases).
* - With primitive arguments, eg. doSomething(int)
* *
* @param classAndMethod a string with the entire class and method name, * @param classAndMethod a string with the entire class and method name, eg.
* eg. "java.lang.System.gc" * "java.lang.System.gc"
* @param params the method parameters * @param params the method parameters
* @throws ClassNotFoundException if the class was not found * @return the return value from this call
* @throws NoSuchMethodException if the class doesn't contain the method */
* @throws InvocationTargetException if an exception occurred in the called public static Object callStaticMethod(String classAndMethod, Object... params) throws Exception {
* method
* @throws IllegalAccessException if the reflection call is not allowed
* @throws IllegalArgumentException if the reflection call arguments are
* wrong
* @return Return value from this call
*/
public static Object callStaticMethod(String classAndMethod, Object ... params) throws ClassNotFoundException,
NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {
int lastDot = classAndMethod.lastIndexOf('.'); int lastDot = classAndMethod.lastIndexOf('.');
String className = classAndMethod.substring(0, lastDot); String className = classAndMethod.substring(0, lastDot);
String methodName = classAndMethod.substring(lastDot + 1); String methodName = classAndMethod.substring(lastDot + 1);
Class< ? >[] paramTypes = getParameterTypesObjects(params); return classMethodInternal(methodName, Class.forName(className), null, params);
Class< ? > c = Class.forName(className);
Method m;
try {
m = c.getMethod(methodName, paramTypes);
} catch (NoSuchMethodException e) {
paramTypes = getParameterTypesPrimitives(params);
m = c.getMethod(methodName, paramTypes);
}
return m.invoke(null, params);
} }
/** /**
* Calls an instance method via reflection. The order in which the method is * Calls an instance method via reflection. This will try to use the method
* searched: * where the most parameter classes match exactly (this algorithm is simpler
* - With object arguments, eg. doSomething(Integer) * than the one in the Java specification, but works well for most cases).
* - With primitive arguments, eg. doSomething(int)
* *
* @param methodName a string with the method name
* @param instance the instance on which the call is done * @param instance the instance on which the call is done
* @param methodName a string with the method name
* @param params the method parameters * @param params the method parameters
* @throws ClassNotFoundException if the class was not found * @return the return value from this call
* @throws NoSuchMethodException if the class doesn't contain the method */
* @throws IllegalArgumentException if the reflection call arguments are public static Object callMethod(Object instance, String methodName, Object... params) throws Exception {
* wrong return classMethodInternal(methodName, instance.getClass(), instance, params);
* @throws IllegalAccessException if the reflection call is not allowed }
* @throws InvocationTargetException if an exception occurred in the called
* method private static Object classMethodInternal(String methodName, Class<?> clazz, Object instance, Object... params) throws Exception {
* @return Return value from this call Method best = null;
*/ int bestMatch = 0;
public static Object callMethod(String methodName, Object instance, Object ... params) throws ClassNotFoundException, boolean isStatic = instance == null;
NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException { for (Method m : clazz.getMethods()) {
Class< ? >[] paramTypes = getParameterTypesObjects(params); if (Modifier.isStatic(m.getModifiers()) == isStatic && m.getName().equals(methodName)) {
int p = match(m.getParameterTypes(), params);
Class< ? > c = instance.getClass(); if (p > bestMatch) {
Method m; bestMatch = p;
try { best = m;
m = c.getMethod(methodName, paramTypes); }
} catch (NoSuchMethodException e) { }
paramTypes = getParameterTypesPrimitives(params); }
m = c.getMethod(methodName, paramTypes); if (best == null) {
throw new NoSuchMethodException(methodName);
} }
return m.invoke(instance, params); return best.invoke(instance, params);
} }
/** /**
* Creates a new instance. The order in which the constructor is searched: * Creates a new instance. This will try to use the constructor where the
* - With object arguments, eg. SomeClass(Integer) * most parameter classes match exactly (this algorithm is simpler than the
* - With primitive arguments, eg. SomeClass(int) * one in the Java specification, but works well for most cases).
* *
* @param className a string with the entire class, eg. "java.lang.Integer" * @param className a string with the entire class, eg. "java.lang.Integer"
* @param params the constructor parameters * @param params the constructor parameters
* @throws ClassNotFoundException if the class was not found
* @throws NoSuchMethodException if the class doesn't contain the
* constructor
* @throws IllegalArgumentException if the reflection call arguments are
* wrong
* @throws InstantiationException if it is not possible to instantiate the
* object
* @throws IllegalAccessException if the reflection call is not allowed
* @throws InvocationTargetException if an exception occurred in the called
* method
* @return the newly created object * @return the newly created object
*/ */
public static Object newInstance(String className, Object ... params) throws ClassNotFoundException, NoSuchMethodException, public static Object newInstance(String className, Object... params) throws Exception {
IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException { Constructor<?> best = null;
Class< ? > c = Class.forName(className); int bestMatch = 0;
Class< ? >[] paramTypes = getParameterTypesObjects(params); for (Constructor<?> c : Class.forName(className).getConstructors()) {
Constructor< ? > constructor; int p = match(c.getParameterTypes(), params);
try { if (p > bestMatch) {
constructor = c.getConstructor(paramTypes); bestMatch = p;
} catch (NoSuchMethodException e) { best = c;
paramTypes = getParameterTypesPrimitives(params); }
constructor = c.getConstructor(paramTypes); }
if (best == null) {
throw new NoSuchMethodException(className);
} }
return best.newInstance(params);
}
return constructor.newInstance(params); private static int match(Class<?>[] params, Object[] values) {
if (params.length == values.length) {
int points = 1;
for (int i=0; i<params.length; i++) {
Class<?> pc = getNonPrimitiveClass(params[i]);
Class<?> vc = values[i].getClass();
if (pc == vc) {
points++;
} else if (!pc.isAssignableFrom(vc)) {
return 0;
}
}
return points;
}
return 0;
} }
/** /**
...@@ -655,18 +644,12 @@ public class Utils { ...@@ -655,18 +644,12 @@ public class Utils {
* *
* @param classAndField a string with the entire class and field name * @param classAndField a string with the entire class and field name
* @return the field value * @return the field value
* @throws ClassNotFoundException if the class was not found
* @throws IllegalAccessException if it is not allowed to access the class
* @throws NoSuchFieldException if the field was not found
*/ */
public static Object getStaticField(String classAndField) throws ClassNotFoundException, IllegalAccessException, NoSuchFieldException { public static Object getStaticField(String classAndField) throws Exception {
int lastDot = classAndField.lastIndexOf('.'); int lastDot = classAndField.lastIndexOf('.');
String className = classAndField.substring(0, lastDot); String className = classAndField.substring(0, lastDot);
String fieldName = classAndField.substring(lastDot + 1); String fieldName = classAndField.substring(lastDot + 1);
return Class.forName(className).getField(fieldName).get(null);
Class< ? > c = Class.forName(className);
Field f = c.getField(fieldName);
return f.get(null);
} }
/** /**
...@@ -675,22 +658,17 @@ public class Utils { ...@@ -675,22 +658,17 @@ public class Utils {
* @param instance the instance on which the call is done * @param instance the instance on which the call is done
* @param fieldName the field name * @param fieldName the field name
* @return the field value * @return the field value
* @throws ClassNotFoundException if the class was not found
* @throws IllegalAccessException if it is not allowed to access the class
* @throws NoSuchFieldException if the field was not found
*/ */
public static Object getField(Object instance, String fieldName) throws ClassNotFoundException, IllegalAccessException, NoSuchFieldException { public static Object getField(Object instance, String fieldName) throws Exception {
Class< ? > c = instance.getClass(); return instance.getClass().getField(fieldName).get(instance);
Field f = c.getField(fieldName);
return f.get(instance);
} }
/** /**
* Returns true if the class is present in the current vm * Returns true if the class is present in the current class loader.
* *
* @param fullyQualifiedClassName a string with the entire class name, eg. * @param fullyQualifiedClassName a string with the entire class name, eg.
* "java.lang.System" * "java.lang.System"
* @return true if the class is present in the current vm * @return true if the class is present
*/ */
public static boolean isClassPresent(String fullyQualifiedClassName) { public static boolean isClassPresent(String fullyQualifiedClassName) {
try { try {
...@@ -701,49 +679,33 @@ public class Utils { ...@@ -701,49 +679,33 @@ public class Utils {
} }
} }
private static Class< ? >[] getParameterTypesObjects(Object... params) { /**
Class< ? >[] paramTypes = new Class[params.length]; * Convert primitive class names to java.lang.* class names.
for (int i = 0; i < params.length; i++) { *
paramTypes[i] = params[i].getClass(); * @param clazz the class (for example: int)
} * @return the non-primitive class (for example: java.lang.Integer)
return paramTypes; */
} public static Class<?> getNonPrimitiveClass(Class<?> clazz) {
if (!clazz.isPrimitive()) {
private static Class< ? >[] getParameterTypesPrimitives(Object... params) { return clazz;
Class< ? >[] paramTypes = new Class[params.length]; } else if (clazz == boolean.class) {
for (int i = 0; i < params.length; i++) { return Boolean.class;
paramTypes[i] = getPrimitiveIfPossible(params[i].getClass()); } else if (clazz == byte.class) {
} return Byte.class;
return paramTypes; } else if (clazz == char.class) {
} return Character.class;
} else if (clazz == double.class) {
private static Class< ? > getPrimitiveIfPossible(Class< ? > clazz) { return Double.class;
if (clazz == Boolean.class) { } else if (clazz == float.class) {
return boolean.class; return Character.class;
} } else if (clazz == int.class) {
if (clazz == Byte.class) { return Integer.class;
return byte.class; } else if (clazz == long.class) {
} return Long.class;
if (clazz == Character.class) { } else if (clazz == short.class) {
return char.class; return Short.class;
} } else if (clazz == void.class) {
if (clazz == Double.class) { return Void.class;
return double.class;
}
if (clazz == Float.class) {
return float.class;
}
if (clazz == Integer.class) {
return int.class;
}
if (clazz == Long.class) {
return long.class;
}
if (clazz == Short.class) {
return short.class;
}
if (clazz == Void.class) {
return void.class;
} }
return clazz; return clazz;
} }
......
...@@ -768,6 +768,9 @@ public class DataType { ...@@ -768,6 +768,9 @@ public class DataType {
if (x == null) { if (x == null) {
return Value.NULL; return Value.NULL;
} }
if (x.isPrimitive()) {
x = Utils.getNonPrimitiveClass(x);
}
if (ResultSet.class.isAssignableFrom(x)) { if (ResultSet.class.isAssignableFrom(x)) {
return Value.RESULT_SET; return Value.RESULT_SET;
} else if (Value.ValueBlob.class.isAssignableFrom(x)) { } else if (Value.ValueBlob.class.isAssignableFrom(x)) {
...@@ -778,21 +781,21 @@ public class DataType { ...@@ -778,21 +781,21 @@ public class DataType {
return Value.STRING; return Value.STRING;
} else if (BigDecimal.class.isAssignableFrom(x)) { } else if (BigDecimal.class.isAssignableFrom(x)) {
return Value.DECIMAL; return Value.DECIMAL;
} else if (Boolean.class.isAssignableFrom(x) || boolean.class.isAssignableFrom(x)) { } else if (Boolean.class == x) {
return Value.BOOLEAN; return Value.BOOLEAN;
} else if (Byte.class.isAssignableFrom(x) || byte.class.isAssignableFrom(x)) { } else if (Byte.class == x) {
return Value.BYTE; return Value.BYTE;
} else if (Short.class.isAssignableFrom(x) || short.class.isAssignableFrom(x)) { } else if (Short.class == x) {
return Value.SHORT; return Value.SHORT;
} else if (Integer.class.isAssignableFrom(x) || int.class.isAssignableFrom(x)) { } else if (Integer.class == x) {
return Value.INT; return Value.INT;
} else if (Character.class.isAssignableFrom(x) || char.class.isAssignableFrom(x)) { } else if (Character.class == x) {
throw DbException.get(ErrorCode.DATA_CONVERSION_ERROR_1, "char (not supported)"); throw DbException.get(ErrorCode.DATA_CONVERSION_ERROR_1, "char (not supported)");
} else if (Long.class.isAssignableFrom(x) || long.class.isAssignableFrom(x)) { } else if (Long.class == x) {
return Value.LONG; return Value.LONG;
} else if (Float.class.isAssignableFrom(x) || float.class.isAssignableFrom(x)) { } else if (Float.class == x) {
return Value.FLOAT; return Value.FLOAT;
} else if (Double.class.isAssignableFrom(x) || double.class.isAssignableFrom(x)) { } else if (Double.class == x) {
return Value.DOUBLE; return Value.DOUBLE;
} else if (byte[].class.isAssignableFrom(x)) { } else if (byte[].class.isAssignableFrom(x)) {
return Value.BYTES; return Value.BYTES;
......
...@@ -35,12 +35,12 @@ public class TestUtils extends TestBase { ...@@ -35,12 +35,12 @@ public class TestUtils extends TestBase {
long currentTimeMillis2 = (Long) Utils.callStaticMethod("java.lang.System.currentTimeMillis"); long currentTimeMillis2 = (Long) Utils.callStaticMethod("java.lang.System.currentTimeMillis");
assertTrue(currentTimeMillis1 <= currentTimeMillis2); assertTrue(currentTimeMillis1 <= currentTimeMillis2);
// New Instance with Integer parameter (Autoboxing) // New Instance with Integer parameter (Autoboxing)
StringBuilder instance = (StringBuilder) Utils.newInstance("java.lang.StringBuilder", new Integer(10)); Object instance = Utils.newInstance("java.lang.StringBuilder", 10);
// New Instance with int parameter // New Instance with int parameter
instance = (StringBuilder) Utils.newInstance("java.lang.StringBuilder", 10); instance = Utils.newInstance("java.lang.StringBuilder", 10);
// Instance methods // Instance methods
Utils.callMethod("append", instance, "abc"); Utils.callMethod(instance, "append", "abc");
int length = (Integer) Utils.callMethod("length", instance); int length = (Integer) Utils.callMethod(instance, "length");
assertEquals(3, length); assertEquals(3, length);
// Static fields // Static fields
String pathSeparator = (String) Utils.getStaticField("java.io.File.pathSeparator"); String pathSeparator = (String) Utils.getStaticField("java.io.File.pathSeparator");
...@@ -51,7 +51,9 @@ public class TestUtils extends TestBase { ...@@ -51,7 +51,9 @@ public class TestUtils extends TestBase {
// Class present? // Class present?
assertFalse(Utils.isClassPresent("abc")); assertFalse(Utils.isClassPresent("abc"));
assertTrue(Utils.isClassPresent(getClass().getName())); assertTrue(Utils.isClassPresent(getClass().getName()));
Utils.callStaticMethod("java.lang.String.valueOf", "a");
Utils.callStaticMethod("java.awt.AWTKeyStroke.getAWTKeyStroke",
'x', java.awt.event.InputEvent.SHIFT_DOWN_MASK);
} }
} }
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论