Установка точек останова на методы внутренних и анонимных классов в JDB

Я пытаюсь работать с 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 использовать имена исходных файлов, как любой нормальный отладчик для любого нормального языка...


person Idan Arye    schedule 14.05.2014    source источник


Ответы (1)


У меня была такая же проблема. В качестве быстрого исправления я просто нашел имя класса (Object в вашем случае) во всех файлах Main$[x].class.

Если вы найдете много из них, вы должны использовать индекс порядка их появления в исходном файле.

person joynes    schedule 13.02.2015