Неожиданный результат с манипулированием байт-кодом Javassist и синтаксисом try-with-resources - PullRequest
0 голосов
/ 01 октября 2019

Я использую Javassist (3.25.0-GA) и Java 8 с пользовательским агентом для преобразования байт-кода и добавления операторов печати в существующие предложения catch{}. Это работает для простых случаев, но имеет проблему с скомпилированным байт-кодом синтаксиса try-with-resources.

Вот основной пример того, что я пытаюсь сделать, и результаты, когда он работает правильно на стандартном try/catch блоков:

    // before byte code manipulation
    public void methodWithCatchClause() {
        try {
            throwsAnException();
        } catch (Exception ex) {
            handleException(ex);
        }
    }
    // after byte code manipulation
    public void methodWithCatchClause() {
        try {
            throwsAnException();
        } catch (Exception ex) {
            System.out.println("CATCH CLAUSE!"); // added by Javassist
            handleException(ex);
        }
    }

Логика, которую я использую для преобразования байт-кода, основана на другом сообщении SO [0]:

    // from https://stackoverflow.com/questions/51738034/javassist-insert-a-method-at-the-beginning-of-catch-block
    ControlFlow cf = new ControlFlow(ctMethod); // ctMethod == methodWithCatchClause()
    for (ControlFlow.Block block : cf.basicBlocks()) {

        ControlFlow.Catcher catchers[] = block.catchers();
        for (int i = 0; i < catchers.length; i++) {
            ControlFlow.Catcher catcher = catchers[i];

            ControlFlow.Block catcherBlock = catcher.block();

            int position = catcherBlock.position();
            int lineNumber = ctMethod.getMethodInfo().getLineNumber(position);

            ctMethod.insertAt(lineNumber + 1, "System.out.println(\"CATCH CLAUSE!\");");
        }
    }

Но этот код не работаетв сочетании с синтаксисом try-with-resources. В качестве конкретного примера этот код:

    public void tryWithResources() {
        try (TestAutoClosable test = new TestAutoClosable()) {
            test.doStuff();
        } catch (Exception ex) {
            handleException(ex);
        }
    }

Превращается в это после генерации кода:

   public void tryWithResources() {
        try {
            TestAutoClosable test = new TestAutoClosable();
            Throwable var2 = null;

            try {
                System.out.println("CATCH CLAUSE!");
                test.doStuff();
            } catch (Throwable var12) {
                var2 = var12;
                throw var12;
            } finally {
                if (test != null) {
                    if (var2 != null) {
                        try {
                            test.close();
                        } catch (Throwable var11) {
                            var2.addSuppressed(var11);
                        }
                    } else {
                        test.close();
                    }
                }

            }
        } catch (Exception var14) {
            System.out.println("CATCH CLAUSE!");
            System.out.println("CATCH CLAUSE!");
            System.out.println("CATCH CLAUSE!");
            // this goes on for 15 more entries...
            this.handleException(var14);
        }

    }

Это, конечно, вызывает "CATCH CLAUSE!"печататься несколько раз в нечетных местах. Возможно, было бы полезно упомянуть, что пустые предложения catch, независимо от синтаксиса try/catch, ломаются аналогичным образом (может быть, основная причина связана?).

Я бы ожидал чего-то более близкого к этому в качестве конечного результата:

    public void tryWithResources() {
        try {
            TestAutoClosable test = new TestAutoClosable();
            Throwable var2 = null;

            try {
                test.noop();
            } catch (Throwable var12) {
                System.out.println("CATCH CLAUSE!");
                var2 = var12;
                throw var12;
            } finally {
                if (test != null) {
                    if (var2 != null) {
                        try {
                            test.close();
                        } catch (Throwable var11) {
                            var2.addSuppressed(var11);
                        }
                    } else {
                        test.close();
                    }
                }

            }
        } catch (Exception var14) {
            this.handleException(var14);
        }

    }

Я пытаюсь выяснить, есть ли у меня простая ошибка в моем коде или мой подход совершенно неправильный. Буду признателен за любую помощь в этом вопросе. Заранее спасибо.

[0] Javassist: вставьте метод в начале блока catch

...