マイペースなプログラミング日記

DTMやプログラミングにお熱なd-kamiがマイペースに書くブログ

Stackとリフレクションを使って変なことをしてみる

Stackにクラス名とメソッド名やフィールド名を突っ込んでそれを実行するプログラムを作った。メソッドを呼び出す場合は引数、引数の数、メソッド名、クラス名、staticでなければオブジェクト。フィールドの場合はフィールド名、クラス名、staticでなければオブジェクトの順でスタックに積む。コンストラクタは引数、引数の数、クラス名で。で、フィールドや返り値、生成したインスタンスはスタックに積む。これをつかってそのうち何かやる

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException ;

import java.util.Stack;

public class Main{
    public static void main(String[] args) throws Exception{
        Stack<Object> stack = new Stack<Object>();
        stack.push("Hello World");
        stack.push(1);
        stack.push("println");
        stack.push("java.io.PrintStream");

        stack.push("out");
        stack.push("java.lang.System");

        stack.push(Main.getField(stack, true));
        stack.push(Main.invokeMethod(stack, false));

        stack.pop();

        stack.push(0);
        stack.push("getHost");
        stack.push("java.net.URL");

        stack.push("http://google.com");
        stack.push(1);
        stack.push("java.net.URL");
        stack.push(Main.callConstructor(stack));

        stack.push(Main.invokeMethod(stack, false));
        System.out.println(stack.pop());
    }

    private static Object callConstructor(Stack<Object> stack)
           throws ClassNotFoundException,  NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {

        String className = stack.pop().toString();

        int parameterCount = Integer.parseInt(stack.pop().toString());

        Class<?>[] types = new Class<?>[parameterCount];
        Object[] args = new Object[parameterCount];

        for(int i = 0; i < parameterCount; i++){
            Object arg = stack.pop();
            types[i] = arg.getClass();
            args[i] = arg;
        }

        return Main.callConstructor(className, types, args);
    }

    private static Object callConstructor(String className, Class<?>[] types, Object[] args)
            throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        Class<?> clazz = Class.forName(className);

        Constructor constructor = clazz.getConstructor(types);
        return constructor.newInstance(args);
    }

   private static Object getField(Stack<Object> stack, boolean isStatic)
            throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException{

       Object target = null;
       if(!isStatic)
           target = stack.pop();

       String className = stack.pop().toString();
       String fieldName = stack.pop().toString();

       return Main.getField(className, target, fieldName);
   }

    private static Object getField(String className, Object target, String fieldName)
            throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException{

        Class<?> clazz = Class.forName(className);
        Field field = clazz.getField(fieldName);
        return field.get(target);
    }

    private static Object invokeMethod(Stack<Object> stack, boolean isStatic)
           throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {

        Object target = null;
        if(!isStatic)
            target = stack.pop();

        String className = stack.pop().toString();

        String methodName = stack.pop().toString();
        int parameterCount = Integer.parseInt(stack.pop().toString());

        Class<?>[] types = new Class<?>[parameterCount];
        Object[] args = new Object[parameterCount];

        for(int i = 0; i < parameterCount; i++){
            Object arg = stack.pop();
            types[i] = arg.getClass();
            args[i] = arg;
        }

        return Main.invokeMethod(className, target, methodName, types, args);
    }

    private static Object invokeMethod(String className, Object target, String methodName, Class<?>[] types, Object[] args)
            throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
        Class<?> clazz = Class.forName(className);

        Method method = clazz.getMethod(methodName, types);
        return method.invoke(target, args);
    }
}