Получить номер строки сценария Nashorn во время интерпретации

В моем коде используется Nashorn для предоставления пользователю функций сценариев, при этом многие классы и функции, реализованные на Java, доступны сценариям через Nashorn.

Одной из задач программы является, конечно, сообщать пользователю о любых ошибках, связанных со сценариями, когда они встречаются. Это очень просто, если происходит ScriptException, так как простое перехват исключения и использование метода getLineNumber() возвращает правильное значение. Однако иногда возникает исключение не из-за синтаксиса, а из-за того, как вызывается код на стороне Java, например, из-за нулевого параметра, который должен был быть допустимым объектом. Они вызывают другие виды исключений, которые все еще можно перехватить при вызове метода eval, но, поскольку у них нет метода getLineNumber(), невозможно угадать, где остался интерпретатор.

Есть ли способ получить последнюю выполненную строку из движка Nashorn?

Код примерно выглядит так:

try {
    engine.eval( script);       
    // successful
    return -1;
} catch ( ScriptException e)
{
    // the ScriptException reports the line number
    return e.getLineNumber();
}
catch ( Exception e)
{
    // is it possible to get the line number here too?
    // ... 
    return lineNumber;
}

person ntrstd11    schedule 02.08.2016    source источник


Ответы (2)


Существует стандартный API Nashorn для получения StackTraceElement[] для «фреймов сценария» из заданного произвольного объекта Throwable.

Класс jdk.nashorn.api.scripting.NashornException имеет

общедоступный статический StackTraceElement [] getScriptFrames (выбрасываемое исключение)

метод

https://docs.oracle.com/javase/8/docs/jdk/api/nashorn/jdk/nashorn/api/scripting/NashornException.html#getScriptFrames-java.lang.Throwable-

Вы можете передать произвольный объект Throwable и получить массив StackTraceElement для фреймов скрипта. Самый верхний кадр сценария будет нулевым элементом массива, и вы можете вызвать getLineNumber для объекта StackTraceElement.

Таким образом, вы можете избежать зависимости от внутренних префиксов пакетов nashorn.

person A. Sundararajan    schedule 03.08.2016

Вы можете пройтись по стеку исключения, найти первый StackTraceElement, где имя класса начинается с jdk.nashorn.internal.scripts., и сообщить его номер строки:

   for(StackTraceElement ste: e.getStackTrace()) {
       if (ste.getClassName().startsWith("jdk.nashorn.internal.scripts.")) {
           return ste.getLineNumber();
       }
   }
   return -1; // couldn't figure it out

Вы также можете попробовать использовать ste.getFileName().endsWith(".js"), если это более надежно для вашей ситуации.

person Attila Szegedi    schedule 02.08.2016