首页 > 解决方案 > 在 Groovy 中为异常或错误添加更多上下文

问题描述

当我只想为发生的任何异常(包括解析错误甚至内存不足)添加更多上下文时,我编写代码如下

    try {
        new JsonSlurper().parseText(response)
    } catch (any) {
        throw new IllegalStateException("Cannot parse response:\n$response", any)
    }

这很好用,但我最终可能会OutOfMemoryError被包裹在IllegalStateException其中听起来不正确,因为进一步可能会有专门的异常处理机制仅用于Errorthrowables。

有什么方法可以为异常添加更多上下文并仍然保留其原始类型或类别?即当我得到时OOME,我想重新抛出Error,当我得到一些解析异常时,我想重新抛出一些未经检查的异常等。当然我不想为每个类别手动执行它,因为OOME这不太可能而且我不会不想为极端情况生成特殊代码(虽然我仍然希望在技术上是正确的)。

标签: exceptiongroovy

解决方案


你绝对可以通过使用它的元编程特性在 groovy 中做到这一点。特别是,对于您的案例,元类提供了您需要的一切。使用它们,您可以动态地将contextData对象添加/附加到exception您希望它携带的对象:

    private static void throwsEnhancedException() throws IOException {
        try {
            throwsBasicException()
        } catch (IOException e) {
            e.metaClass.contextData = "My context data"
            throw e;
        }
    }

然后要contextData在代码的其他部分检索它,只需exception像这样检查对象:

    private static void doSomethingWithContextData(Closure contextDataHandler) throws IOException {
        try {
            throwsEnhancedException();
        } catch (IOException e) {
            // RETRIEVE `contextData` FROM `e` OR NULL IF THE PROPERTY DO NOT EXIST
            def contextData = e.hasProperty('contextData')?.getProperty(e)

            // DO SOMETHING WITH `contextData`
            contextDataHandler(contextData)
        }
    }

在那里,我使用这个论点contextDataHandler作为一种灵活的方式Closure来处理contextData

以下是一个完整的工作演示:

import java.time.LocalDateTime

class ExceptionEnhancer {
    static void main(String[] args) {
        def logger = { println "${LocalDateTime.now()} - Context Data = [$it]" }
        doSomethingWithContextData logger
    }

    private static void doSomethingWithContextData(Closure contextDataHandler) throws IOException {
        try {
            throwsEnhancedException();
        } catch (IOException e) {
            // RETRIEVE `contextData` FROM `e` OR NULL IF THE PROPERTY DO NOT EXIST
            def contextData = e.hasProperty('contextData')?.getProperty(e)

            // DO SOMETHING WITH `contextData`
            contextDataHandler(contextData)
        }
    }

    private static void throwsEnhancedException() throws IOException {
        try {
            throwsBasicException()
        } catch (IOException e) {
            e.metaClass.contextData = "My context data"
            throw e;
        }
    }

    public static void throwsBasicException() throws IOException {
        throw new IOException();
    }
}

GitHub上的完整代码

希望这可以帮助。


推荐阅读