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

Reflection utilities.

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