package edu.pdx.cs410J.grader;
import java.lang.reflect.*;
import java.io.*;
import java.util.*;
/**
* This program uses Java reflection to invoke a static method of a
* given class.
*/
public class InvokeStatic {
private static PrintStream out = System.out;
private static PrintStream err = System.err;
private static final boolean VERBOSE =
Boolean.getBoolean("InvokeStatic.VERBOSE");
/**
* Turns a string into the an instance of the given type. Array
* elements are separated by a space.
*/
private static Object parseParam(String param, Class type)
throws Throwable {
if (type.isArray()) {
Class elementType = type.getComponentType();
StringTokenizer st = new StringTokenizer(param, " ");
List<Object> elements = new ArrayList<Object>();
while (st.hasMoreTokens()) {
elements.add(parseParam(st.nextToken(), elementType));
}
Object array = Array.newInstance(elementType, elements.size());
for (int i = 0; i < elements.size(); i++) {
Array.set(array, i, elements.get(i));
}
return array;
} else {
// The type must have a constructor that takes a string argument
if (type.equals(Character.TYPE)) {
type = Character.class;
} else if (type.equals(Boolean.TYPE)) {
type = Boolean.class;
} else if (type.equals(Byte.TYPE)) {
type = Byte.class;
} else if (type.equals(Short.TYPE)) {
type = Short.class;
} else if (type.equals(Integer.TYPE)) {
type = Integer.class;
} else if (type.equals(Long.TYPE)) {
type = Long.class;
} else if (type.equals(Float.TYPE)) {
type = Float.class;
} else if (type.equals(Double.TYPE)) {
type = Double.class;
}
Constructor init =
type.getConstructor(new Class[] { String.class });
return init.newInstance(new Object[] { param });
}
}
/**
* This method converts a string into a Class type. Array types are
* denoted with a preceeding "[".
*/
private static Class parseType(String name)
throws ClassNotFoundException {
int lastBracket = name.lastIndexOf('[');
if (lastBracket == -1) {
// Not an array type
if (name.equals("char")) {
return Character.TYPE;
} else if (name.equals("boolean")) {
return Boolean.TYPE;
} else if (name.equals("byte")) {
return Byte.TYPE;
} else if (name.equals("short")) {
return Short.TYPE;
} else if (name.equals("int")) {
return Integer.TYPE;
} else if (name.equals("long")) {
return Long.TYPE;
} else if (name.equals("float")) {
return Float.TYPE;
} else if (name.equals("double")) {
return Double.TYPE;
} else {
return Class.forName(name);
}
} else {
// Array type
String className = name.substring(lastBracket + 1);
Class elementType = parseType(className);
int[] dimensions = new int[lastBracket + 1];
for (int i = 0; i < dimensions.length; i++) {
dimensions[i] = 0;
}
return Array.newInstance(elementType, dimensions).getClass();
}
}
/**
* Returns a default value for a given type. If the type is an
* array type, then it returns an empty array of that type.
* Otherwise, it returns <code>null</code>.
*/
private static Object getDefaultValueFor(Class type) {
if (type.isArray()) {
return Array.newInstance(type.getComponentType(), 0);
} else {
return null;
}
}
/**
* Prints usage information for this program
*/
private static void usage(String s) {
err.println("\n** " + s + "\n");
err.println("usage java InvokeStatic className methodName " +
"[paramTypes] [(param)*]");
err.println(" className The name of the class containing the "
+ "static method");
err.println(" methodName The name of the static method");
err.println(" paramTypes The types of the method's arguments " +
"(defaults to an array of");
err.println(" param An argument to the method (defaults "
+ "to an empty array of");
err.println(" Strings");
err.println(" Strings");
err.println("");
System.exit(1);
}
public static void main(String[] args) throws Throwable {
String className = null;
String methodName = null;
String paramTypes = null;
List<String> params = new ArrayList<String>();
// Parse the command line
for (int i = 0; i < args.length; i++) {
if (className == null) {
className = args[i];
} else if (methodName == null) {
methodName = args[i];
} else if (paramTypes == null) {
paramTypes = args[i];
} else {
// It's an arguement
params.add(args[i]);
}
}
if (className == null) {
usage("Missing class name");
}
if (methodName == null) {
usage("Missing method name");
}
if (paramTypes == null) {
paramTypes = ""; // "[java.lang.String";
}
// if (params.isEmpty()) {
// params.add("");
// }
// Translate the methodArgsTypes into types
List<Object> argsTypes = new ArrayList<Object>();
StringTokenizer st = new StringTokenizer(paramTypes, ";");
while (st.hasMoreTokens()) {
argsTypes.add(parseType(st.nextToken()));
}
Class[] types = (Class[]) argsTypes.toArray(new Class[0]);
List<Object> actuals = new ArrayList<Object>();
// Translate the parameters into objects
for (int i = 0; i < types.length; i++) {
Class type = types[i];
if (params.isEmpty()) {
actuals.add(getDefaultValueFor(type));
} else if (type.isArray()) {
// The params are elements of the array
Class elementType = type.getComponentType();
Object array = Array.newInstance(elementType, params.size());
for (int j = 0; j < params.size(); j++) {
String param = (String) params.get(j);
Array.set(array, j, parseParam(param, elementType));
}
actuals.add(array);
} else {
String param = (String) params.get(i);
actuals.add(parseParam(param, type));
}
}
// Make sure that the number of parameter types equals the number
// of parameters
if (!actuals.isEmpty() && types.length != actuals.size()) {
String s = "Param mismatch: " + types.length +
" param types and " + actuals.size() + " params";
throw new IllegalArgumentException(s);
}
if (VERBOSE) {
StringBuffer sb = new StringBuffer();
sb.append("Invoking ");
sb.append(className);
sb.append(".");
sb.append(methodName);
sb.append("(");
for (int i = 0; i < types.length; i++) {
sb.append(types[i].getName());
if (i != types.length - 1) {
sb.append(", ");
}
}
sb.append(")");
out.println(sb.toString());
out.println("params are " + actuals);
}
Class c = Class.forName(className);
Method m = c.getDeclaredMethod(methodName, types);
m.setAccessible(true);
try {
Object value = m.invoke(null, actuals.toArray());
if (!m.getReturnType().equals(Void.TYPE)) {
System.out.println("\nMethod returned: " + value);
}
} catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
}