challenge ローカル変数の一覧を取得

リフレクション系のお題の続編です。 ローカル変数の内容を取得して連想配列(ハッシュ、辞書など)に詰める コードを書いてください。

Pythonで表現すると、下のコードの???部分を埋めることになります。

>>> def foo():
	x = 1
	y = "hello"
	???
	return result

>>> foo()
{'y': 'hello', 'x': 1}

Posted feedbacks - Java

コンパイルオプションで -g を指定することでクラスファイルにローカル変数名を入れることができるのですが、それを認識するAPIはありません。 クラスパスからクラスファイルを取得・解析してローカル変数名を取得することも多分可能ですが、変数名に対応する値を取得する方法がありません。 どうしようもないので内部クラスを使って似たようなことをやってみました。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import java.util.HashMap;
import java.util.Map;

import java.lang.reflect.Field;

public class Test {
	public static void main(String[] args) {
		Map map = foo();
		System.out.println(map);
	}
	static Map foo() {
		Map map = new HashMap();
		class Hoge {
			int x = 1;
			String y = "hello";
			
			Hoge() {
			}
		}
		
		Hoge hoge = new Hoge();
		Field[] fields = hoge.getClass().getDeclaredFields();
		for (int i = 0; i < fields.length; i++) {
			try {
				map.put(fields[i].getName(), fields[i].get(hoge));
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return map;
	}
}

ローカル変数の取得はリフレクションというよりはデバッグ用という感じがします。
そこで、Java Debug Interface を使ってみました。

public class Sample {
    public static void main(String[] args) {
        int x = 1;
        String y = "hello";
    }
}

というサンプルの場合は、-g オプションつきで Sample をコンパイルした後に、
    java TinyDB Sample
で起動すると、mainメソッドのローカル変数(引数つき)が出力されます。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import com.sun.jdi.*;
import com.sun.jdi.connect.LaunchingConnector;
import com.sun.jdi.connect.Connector;
import com.sun.jdi.event.*;
import com.sun.jdi.request.*;
import java.util.Map;

public class TinyDB {
    public static void main(String[] args) throws Exception {
        LaunchingConnector lc = Bootstrap.virtualMachineManager().
            defaultConnector();
        Map<String, Connector.Argument> arg = lc.defaultArguments();
        arg.get("main").setValue(args[0]);

        VirtualMachine vm = lc.launch(arg);
        EventQueue q = vm.eventQueue();
        EventSet e = q.remove(); // get VMStartEvent
        EventRequestManager mgr = vm.eventRequestManager();
        MethodExitRequest exitReq = mgr.createMethodExitRequest();
        exitReq.addClassFilter(args[0]);
        exitReq.enable();
        e.resume();
        e = q.remove(); // MethodExitEvent
        LocatableEvent ev = (LocatableEvent)e.eventIterator().nextEvent();
        ThreadReference tr = ev.thread();
        StackFrame frame = tr.frame(0);
        for (LocalVariable var : frame.visibleVariables()) {
            System.out.print(var.name() + ": ");
            Value val = frame.getValue(var);
            if (val instanceof PrimitiveValue) {
                System.out.println(((PrimitiveValue)val).doubleValue());
            } else if (val instanceof StringReference) {
                System.out.println(((StringReference)val).value());
            } else if (val instanceof ObjectReference) {
                System.out.println(val.type().name());
            }
        }

        e.resume();
        e = q.remove(); // get VMDisconnectEvent
    }
}

Index

Feed

Other

Link

Pathtraq

loading...