Я пытаюсь работать с JDB программно. В отличие от любого здравомыслящего отладчика, JDB обращается к исходному коду, используя имена классов, а не имена исходных файлов. Я предполагаю, что это связано с тем, что байт-код хранится в нескольких файлах .class, а не в одном файле (вы ожидаете, что компиляция с флагом -g
создаст некоторую ссылку на исходные файлы, но упрощение - это не путь Java. .)
Когда JDB ссылается на классы, я обычно могу выполнить некоторые манипуляции со строками и посмотреть на имена исходных файлов, чтобы выяснить, какой исходный файл объявляет соответствующий класс. Когда мне нужно предоставить имя класса для точки останова, я могу прочитать файл, чтобы получить имя пакета, использовать имя файла в качестве имени класса и таким образом сгенерировать полное имя класса. Эти два случая у меня заработали.
Проблема начинается с внутренних классов и анонимных классов. Они находятся в своих собственных файлах классов, а их имена являются искаженными версиями класса, который их содержит. Чтобы установить там точку останова, мне нужно искаженное имя.
Например - это Main.java
(+номера строк):
1: public class Main{
2: public static void main(String[] args){
3: new Object(){
4: @Override public String toString(){
5: System.out.println("hi");
6: return "";
7: }
8: }.toString();
9: }
10:}
Я скомпилировал его с помощью javac -g Main.java
и получил Main.class
и Main$1.class
. Я бегу jdb
:
Initializing jdb ...
> stop on Main.main
Deferring breakpoint Main.main.
It will be set after the class is loaded.
> run Main
run Main
Set uncaught java.lang.Throwable
Set deferred uncaught java.lang.Throwable
>
VM Started: Set deferred breakpoint Main.main
Breakpoint hit: "thread=main", Main.main(), line=3 bci=0
3 new Object(){
(Мне нужна была эта часть для загрузки Main.class
, иначе я бы просто получил "Это будет установлено после загрузки класса" для всех попыток установки точки останова.)
Если я устанавливаю точку останова для строки 8, она работает правильно:
main[1] stop at Main:8
Set breakpoint Main:8
Если я устанавливаю точку останова для строки 5, которая является частью анонимного класса, я получаю сообщение об ошибке:
main[1] stop at Main:5
Unable to set breakpoint Main:5 : No code at line 5 in Main
Строка 5 явно содержит код — проблема в том, что код не скомпилирован в Main.class
— он скомпилирован в Main$1.class
, поэтому вместо этого мне нужно написать:
main[1] stop at Main$1:5
Deferring breakpoint Main$1:5.
It will be set after the class is loaded.
Теперь то, как Java разбивает байт-код на файлы .class, является детерминированным, и в этом простом примере легко понять, что и куда идет, если вы исследуете его человеческими глазами, но мне нужен способ программно вычислить искаженные имена классов ( с VimScript) для реальных исходных файлов. Попытка синтаксически проанализировать исходный файл и выяснить, что является слишком сложной задачей - должен быть более простой способ.
Может быть, извлечь эту информацию из файлов .class, или спросить об этом JDB, или даже заставить JDB использовать имена исходных файлов, как любой нормальный отладчик для любого нормального языка...