Touching the heart: coercing
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@940523 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/shell/Reflective.java b/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/shell/Reflective.java
index 901e45e..e7e8ddd 100644
--- a/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/shell/Reflective.java
+++ b/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/shell/Reflective.java
@@ -18,369 +18,349 @@
*/
package org.apache.felix.gogo.runtime.shell;
-import java.lang.reflect.Array;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
+import java.lang.annotation.*;
+import java.lang.reflect.*;
+import java.util.*;
-import org.osgi.service.command.CommandSession;
+import org.osgi.service.command.*;
-public class Reflective
-{
- public final static Object NO_MATCH = new Object();
- public final static Set<String> KEYWORDS = new HashSet<String>(
- Arrays.asList(new String[] { "abstract", "continue", "for", "new", "switch",
- "assert", "default", "goto", "package", "synchronized", "boolean", "do",
- "if", "private", "this", "break", "double", "implements", "protected",
- "throw", "byte", "else", "import", "public", "throws", "case", "enum",
- "instanceof", "return", "transient", "catch", "extends", "int", "short",
- "try", "char", "final", "interface", "static", "void", "class",
- "finally", "long", "strictfp", "volatile", "const", "float", "native",
- "super", "while" }));
- public final static String MAIN = "_main";
+public class Reflective {
+ public final static Object NO_MATCH = new Object();
+ public final static Set<String> KEYWORDS = new HashSet<String>(Arrays
+ .asList(new String[] { "abstract", "continue", "for", "new",
+ "switch", "assert", "default", "goto", "package",
+ "synchronized", "boolean", "do", "if", "private", "this",
+ "break", "double", "implements", "protected", "throw",
+ "byte", "else", "import", "public", "throws", "case",
+ "enum", "instanceof", "return", "transient", "catch",
+ "extends", "int", "short", "try", "char", "final",
+ "interface", "static", "void", "class", "finally", "long",
+ "strictfp", "volatile", "const", "float", "native",
+ "super", "while" }));
+ public final static String MAIN = "_main";
- public Object method(CommandSession session, Object target, String name,
- List<Object> args) throws IllegalArgumentException, IllegalAccessException,
- InvocationTargetException, Exception
- {
- Method[] methods = target.getClass().getMethods();
- name = name.toLowerCase();
+ public Object method(CommandSession session, Object target, String name,
+ List<Object> args) throws IllegalArgumentException,
+ IllegalAccessException, InvocationTargetException, Exception {
+ Method[] methods = target.getClass().getMethods();
+ name = name.toLowerCase();
- String get = "get" + name;
- String is = "is" + name;
- String set = "set" + name;
+ String get = "get" + name;
+ String is = "is" + name;
+ String set = "set" + name;
- if (KEYWORDS.contains(name))
- {
- name = "_" + name;
- }
+ if (KEYWORDS.contains(name)) {
+ name = "_" + name;
+ }
- if (target instanceof Class)
- {
- Method[] staticMethods = ((Class<?>) target).getMethods();
- for (Method m : staticMethods)
- {
- String mname = m.getName().toLowerCase();
- if (mname.equals(name) || mname.equals(get) || mname.equals(set)
- || mname.equals(is) || mname.equals(MAIN))
- {
- methods = staticMethods;
- break;
- }
- }
- }
+ if (target instanceof Class) {
+ Method[] staticMethods = ((Class<?>) target).getMethods();
+ for (Method m : staticMethods) {
+ String mname = m.getName().toLowerCase();
+ if (mname.equals(name) || mname.equals(get)
+ || mname.equals(set) || mname.equals(is)
+ || mname.equals(MAIN)) {
+ methods = staticMethods;
+ break;
+ }
+ }
+ }
- Method bestMethod = null;
- Object[] bestArgs = null;
- int match = -1;
- ArrayList<Class<?>[]> possibleTypes = new ArrayList<Class<?>[]>();
+ Method bestMethod = null;
+ Object[] bestArgs = null;
+ int match = -1;
+ ArrayList<Class<?>[]> possibleTypes = new ArrayList<Class<?>[]>();
- for (Method m : methods)
- {
- String mname = m.getName().toLowerCase();
- if (mname.equals(name) || mname.equals(get) || mname.equals(set)
- || mname.equals(is) || mname.equals(MAIN))
- {
- Class<?>[] types = m.getParameterTypes();
- ArrayList<Object> xargs = new ArrayList<Object>(args);
+ for (Method m : methods) {
+ String mname = m.getName().toLowerCase();
+ if (mname.equals(name) || mname.equals(get) || mname.equals(set)
+ || mname.equals(is) || mname.equals(MAIN)) {
+ Class<?>[] types = m.getParameterTypes();
+ ArrayList<Object> xargs = new ArrayList<Object>(args);
- // pass command name as argv[0] to main, so it can handle multiple commands
- if (mname.equals(MAIN))
- {
- xargs.add(0, name);
- }
+ // pass command name as argv[0] to main, so it can handle
+ // multiple commands
+ if (mname.equals(MAIN)) {
+ xargs.add(0, name);
+ }
- // Check if the command takes a session
- if (types.length > 0 && CommandSession.class.isAssignableFrom(types[0]))
- {
- xargs.add(0, session);
- }
+ // Check if the command takes a session
+ if (types.length > 0
+ && CommandSession.class.isAssignableFrom(types[0])) {
+ xargs.add(0, session);
+ }
- Object[] parms = new Object[types.length];
- // if (types.length >= args.size() ) {
- int local = coerce(session, target, types, parms, xargs);
- if ((local >= xargs.size()) && (local >= types.length))
- { // derek - stop no-args
- boolean exact = (local == xargs.size() && local == types.length);
- if (exact || local > match)
- {
- bestMethod = m;
- bestArgs = parms;
- match = local;
- }
- if (exact)
- {
- break;
- }
- }
- else
- {
- possibleTypes.add(types);
- }
- // }
- // if (match == -1 && types.length == 1
- // && types[0] == Object[].class) {
- // bestMethod = m;
- // Object value = args.toArray();
- // bestArgs = new Object[] { value };
- // }
- }
- }
+ Object[] parms = new Object[types.length];
+ // if (types.length >= args.size() ) {
+ int local = coerce(session, target, m, types, parms, xargs);
+ if ((local >= xargs.size()) && (local >= types.length)) { // derek
+ // -
+ // stop
+ // no-args
+ boolean exact = (local == xargs.size() && local == types.length);
+ if (exact || local > match) {
+ bestMethod = m;
+ bestArgs = parms;
+ match = local;
+ }
+ if (exact) {
+ break;
+ }
+ } else {
+ possibleTypes.add(types);
+ }
+ // }
+ // if (match == -1 && types.length == 1
+ // && types[0] == Object[].class) {
+ // bestMethod = m;
+ // Object value = args.toArray();
+ // bestArgs = new Object[] { value };
+ // }
+ }
+ }
- if (bestMethod != null)
- {
- bestMethod.setAccessible(true);
- // derek: BUGFIX catch InvocationTargetException
- // return bestMethod.invoke(target, bestArgs);
- try
- {
- return bestMethod.invoke(target, bestArgs);
- }
- catch (InvocationTargetException e)
- {
- Throwable cause = e.getCause();
- if (cause instanceof Exception)
- {
- throw (Exception) cause;
- }
- throw e;
- }
- }
- else
- {
- //throw new IllegalArgumentException("Cannot find command:" + name + " with args:" + args);
- // { derek
- ArrayList<String> list = new ArrayList<String>();
- for (Class<?>[] types : possibleTypes)
- {
- StringBuilder buf = new StringBuilder();
- buf.append('(');
- for (Class<?> type : types)
- {
- if (buf.length() > 1)
- {
- buf.append(", ");
- }
- buf.append(type.getSimpleName());
- }
- buf.append(')');
- list.add(buf.toString());
- }
+ if (bestMethod != null) {
+ bestMethod.setAccessible(true);
+ // derek: BUGFIX catch InvocationTargetException
+ // return bestMethod.invoke(target, bestArgs);
+ try {
+ return bestMethod.invoke(target, bestArgs);
+ } catch (InvocationTargetException e) {
+ Throwable cause = e.getCause();
+ if (cause instanceof Exception) {
+ throw (Exception) cause;
+ }
+ throw e;
+ }
+ } else {
+ // throw new IllegalArgumentException("Cannot find command:" + name
+ // + " with args:" + args);
+ // { derek
+ ArrayList<String> list = new ArrayList<String>();
+ for (Class<?>[] types : possibleTypes) {
+ StringBuilder buf = new StringBuilder();
+ buf.append('(');
+ for (Class<?> type : types) {
+ if (buf.length() > 1) {
+ buf.append(", ");
+ }
+ buf.append(type.getSimpleName());
+ }
+ buf.append(')');
+ list.add(buf.toString());
+ }
- throw new IllegalArgumentException(String.format(
- "Cannot coerce %s%s to any of %s", name, args, list));
- // } derek
- }
- }
+ throw new IllegalArgumentException(String.format(
+ "Cannot coerce %s%s to any of %s", name, args, list));
+ // } derek
+ }
+ }
- /**
- * Complex routein to convert the arguments given from the command line to
- * the arguments of the method call. First, an attempt is made to convert
- * each argument. If this fails, a check is made to see if varargs can be
- * applied. This happens when the last method argument is an array.
- *
- * @param session
- * @param target
- * @param types
- * @param out
- * @param in
- * @return
- * @throws Exception
- */
- @SuppressWarnings("unchecked")
- private int coerce(CommandSession session, Object target, Class<?> types[],
- Object out[], List<Object> in) throws Exception
- {
- int i = 0;
- while (i < out.length)
- {
- out[i] = null;
- try
- {
- // Try to convert one argument
- // derek: add empty array as extra argument
- //out[i] = coerce(session, target, types[i], in.get(i));
- if (i == in.size())
- {
- out[i] = NO_MATCH;
- }
- else
- {
- out[i] = coerce(session, target, types[i], in.get(i));
- }
+ /**
+ * Complex routein to convert the arguments given from the command line to
+ * the arguments of the method call. First, an attempt is made to convert
+ * each argument. If this fails, a check is made to see if varargs can be
+ * applied. This happens when the last method argument is an array.
+ *
+ * @param session
+ * @param target
+ * @param m
+ * @param types
+ * @param out
+ * @param in
+ * @return
+ * @throws Exception
+ */
+ @SuppressWarnings("unchecked")
+ private int coerce(CommandSession session, Object target, Method m,
+ Class<?> types[], Object out[], List<Object> in) throws Exception {
+ Annotation[][] pas = m.getParameterAnnotations();
- if (out[i] == NO_MATCH)
- {
- // Failed
- // No match, check for varargs
- if (types[i].isArray() && i == types.length - 1)
- {
- // Try to parse the remaining arguments in an array
- Class<?> component = types[i].getComponentType();
- Object components = Array.newInstance(component, in.size() - i);
- int n = i;
- while (i < in.size())
- {
- Object t = coerce(session, target, component, in.get(i));
- if (t == NO_MATCH)
- {
- return -1;
- }
- Array.set(components, i - n, t);
- i++;
- }
- out[n] = components;
- // Is last element, so we will quite hereafter
- // return n;
- if (i == in.size())
- {
- ++i;
- }
- return i; // derek - return number of args converted
- }
- return -1;
- }
- i++;
- }
- catch (Exception e)
- {
- System.err.println("Reflective:" + e);
- e.printStackTrace();
+ for (int argIndex = 0; argIndex < pas.length; argIndex++) {
+ Annotation as[] = pas[argIndex];
+ for (int a = 0; a < as.length; a++) {
+ if (as[a].getClass() == Option.class) {
+ Option o = (Option) as[a];
+ out[argIndex] = coerce(session, target, types[argIndex], o
+ .dflt());
+ } else if (as[a].getClass() == Flag.class) {
+ Flag o = (Flag) as[a];
+ out[argIndex] = coerce(session, target, types[argIndex],
+ false);
+ }
+ }
+ }
- // should get rid of those exceptions, but requires
- // reg ex matching to see if it throws an exception.
- // dont know what is better
- return -1;
- }
- }
- return i;
- }
+
+ in = new ArrayList(in);
+ for (Iterator<Object> i = in.iterator(); i.hasNext();) {
+ Object item = i.next();
+ if (item instanceof String) {
+ String option = (String) item;
+ if (option.startsWith("-")) {
+ for (int argIndex = 0; argIndex < pas.length; argIndex++) {
+ Annotation as[] = pas[argIndex];
+ for (int a = 0; a < as.length; a++) {
+ if (as[a].getClass() == Option.class) {
+ Option o = (Option) as[a];
+ if (o.name().equals(option)) {
+ i.remove();
+ assert i.hasNext();
+ Object value = i.next();
+ i.remove();
+ out[argIndex] = coerce(session, target,
+ types[argIndex], value);
+ }
+ } else if (as[a].getClass() == Flag.class) {
+ Flag o = (Flag) as[a];
+ if (o.name().equals(option)) {
+ i.remove();
+ out[argIndex] = coerce(session, target,
+ types[argIndex], true);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ int start = 0;
+ while (start < out.length) {
+ out[start] = null;
+ try {
+ // Try to convert one argument
+ // derek: add empty array as extra argument
+ // out[i] = coerce(session, target, types[i], in.get(i));
+ if (start == in.size()) {
+ out[start] = NO_MATCH;
+ } else {
+ out[start] = coerce(session, target, types[start], in.get(start));
+ }
- Object coerce(CommandSession session, Object target, Class<?> type, Object arg)
- throws Exception
- {
- if (arg == null)
- {
- return null;
- }
+ if (out[start] == NO_MATCH) {
+ // Failed
+ // No match, check for varargs
+ if (types[start].isArray() && start == types.length - 1) {
+ // Try to parse the remaining arguments in an array
+ Class<?> component = types[start].getComponentType();
+ Object components = Array.newInstance(component, in
+ .size()
+ - start);
+ int n = start;
+ while (start < in.size()) {
+ Object t = coerce(session, target, component, in
+ .get(start));
+ if (t == NO_MATCH) {
+ return -1;
+ }
+ Array.set(components, start - n, t);
+ start++;
+ }
+ out[n] = components;
+ // Is last element, so we will quite hereafter
+ // return n;
+ if (start == in.size()) {
+ ++start;
+ }
+ return start; // derek - return number of args converted
+ }
+ return -1;
+ }
+ start++;
+ } catch (Exception e) {
+ System.err.println("Reflective:" + e);
+ e.printStackTrace();
- if (type.isAssignableFrom(arg.getClass()))
- {
- return arg;
- }
+ // should get rid of those exceptions, but requires
+ // reg ex matching to see if it throws an exception.
+ // dont know what is better
+ return -1;
+ }
+ }
+ return start;
+ }
- Object converted = session.convert(type, arg);
- if (converted != null)
- {
- return converted;
- }
+ Object coerce(CommandSession session, Object target, Class<?> type,
+ Object arg) throws Exception {
+ if (arg == null) {
+ return null;
+ }
- String string = arg.toString();
- if (type.isAssignableFrom(String.class))
- {
- return string;
- }
+ if (type.isAssignableFrom(arg.getClass())) {
+ return arg;
+ }
- if (type.isArray())
- {
- // Must handle array types
- return NO_MATCH;
- }
- else
- {
- if (!type.isPrimitive())
- {
- try
- {
- return type.getConstructor(String.class).newInstance(string);
- }
- catch (Exception e)
- {
- return NO_MATCH;
- }
- }
- }
+ Object converted = session.convert(type, arg);
+ if (converted != null) {
+ return converted;
+ }
- try
- {
- if (type == boolean.class)
- {
- return new Boolean(string);
- }
- else
- {
- if (type == byte.class)
- {
- return new Byte(string);
- }
- else
- {
- if (type == char.class)
- {
- if (string.length() == 1)
- {
- return string.charAt(0);
- }
- }
- else
- {
- if (type == short.class)
- {
- return new Short(string);
- }
- else
- {
- if (type == int.class)
- {
- return new Integer(string);
- }
- else
- {
- if (type == float.class)
- {
- return new Float(string);
- }
- else
- {
- if (type == double.class)
- {
- return new Double(string);
- }
- else
- {
- if (type == long.class)
- {
- return new Long(string);
- }
- }
- }
- }
- }
- }
- }
- }
- }
- catch (NumberFormatException e)
- {
- }
+ String string = arg.toString();
+ if (type.isAssignableFrom(String.class)) {
+ return string;
+ }
- return NO_MATCH;
- }
+ if (type.isArray()) {
+ // Must handle array types
+ return NO_MATCH;
+ } else {
+ if (!type.isPrimitive()) {
+ try {
+ return type.getConstructor(String.class)
+ .newInstance(string);
+ } catch (Exception e) {
+ return NO_MATCH;
+ }
+ }
+ }
- public static boolean hasCommand(Object target, String function)
- {
- Method[] methods = target.getClass().getMethods();
- for (Method m : methods)
- {
- if (m.getName().equals(function))
- {
- return true;
- }
- }
- return false;
- }
+ try {
+ if (type == boolean.class) {
+ return new Boolean(string);
+ } else {
+ if (type == byte.class) {
+ return new Byte(string);
+ } else {
+ if (type == char.class) {
+ if (string.length() == 1) {
+ return string.charAt(0);
+ }
+ } else {
+ if (type == short.class) {
+ return new Short(string);
+ } else {
+ if (type == int.class) {
+ return new Integer(string);
+ } else {
+ if (type == float.class) {
+ return new Float(string);
+ } else {
+ if (type == double.class) {
+ return new Double(string);
+ } else {
+ if (type == long.class) {
+ return new Long(string);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ } catch (NumberFormatException e) {
+ }
+
+ return NO_MATCH;
+ }
+
+ public static boolean hasCommand(Object target, String function) {
+ Method[] methods = target.getClass().getMethods();
+ for (Method m : methods) {
+ if (m.getName().equals(function)) {
+ return true;
+ }
+ }
+ return false;
+ }
}