Repetitive try-catch blocks with Groovy 'with&

2019-02-22 17:28发布

I have the following Groovy class:

@Slf4j
class WidgetService {
    WidgetDao widgetDao = new WidgetDao()

    createWidget(String name, int type) {
        try {
            widgetDao.createWidget(name, type)
        } catch(WidgetException wexc) {
            log.error(wexc)
            int x = doFizz()
            long y = doBuzz(x)
            determineHowToHandle(y)
        }
    }

    Widget getWidgetById(Long id) {
        try {
            widgetDao.getWidgetById(id)
        } catch(WidgetException wexc) {
            log.error(wexc)
            int x = doFizz()
            long y = doBuzz(x)
            determineHowToHandle(y)
        }
    }

    Widget getWidgetByName(String name) {
        try {
            widgetDao.getWidgetByName(name)
        } catch(WidgetException wexc) {
            log.error(wexc)
            int x = doFizz()
            long y = doBuzz(x)
            determineHowToHandle(y)
        }
    }

    def deleteWidget(Widget w) {
        try {
            widgetDao.deleteWidget(w)
        } catch(WidgetException wexc) {
            log.error(wexc)
            int x = doFizz()
            long y = doBuzz(x)
            determineHowToHandle(y)
        }
    }

    ...dozens of more methods with *exact* same catch block
}

As you can see I have a lot of duplicate, boilerplate code in my try-catch blocks. It would be nice if I could define a closure or some sort of AOP-based handler just pass the widgetDao method-of-interest into the closure/handler as a lambda or something similar:

def createWidgetClosure = { it =>
    widgetDao.createWidget(it.name, it.type)
}

def getWidgetByIdClosure = { it =>
    widgetDao.getWidgetById(it.id)
}

def tryCatchClosure = { closure =>
    try {
        closure()
    } catch(WidgetException wexc) {
        log.error(wexc)
        int x = doFizz()
        long y = doBuzz(x)
        determineHowToHandle(y)
    }
}

So that my `WidgetService could then look something like this:

@Slf4j
class WidgetService {
    WidgetDao widgetDao = new WidgetDao()

    createWidget(String name, int type) {
        tryCatchClosure(createWidgetClosure())
    }

    Widget getWidgetById(Long id) {
        tryCatchClosure(getWidgetByIdClosure())
    }

    ...dozens of more methods with *exact* same catch block
}

Is this possible? If so, how?

1条回答
Luminary・发光体
2楼-- · 2019-02-22 18:28

You can simply do as below by using tryCatchClosure what you have now. You can even make tryCatchClosure a method which takes Closure as a parameter.

class WidgetService {
    WidgetDao widgetDao = new WidgetDao()

    def tryCatchClosure(Closure closure) {
        try {
            closure()
        } catch(WidgetException wexc) {
            log.error(wexc)
            int x = doFizz()
            long y = doBuzz(x)
            determineHowToHandle(y)
        }
    }

    createWidget(String name, int type) {
        tryCatchClosure {
            widgetDao.createWidget(name, type)
        } 
    }

    Widget getWidgetById(Long id) {
        tryCatchClosure {
            widgetDao.getWidgetById(id)
        }
    }

    Widget getWidgetByName(String name) {
        tryCatchClosure {
            widgetDao.getWidgetByName(name)
        }
    }

    def deleteWidget(Widget w) {
        tryCatchClosure {
            widgetDao.deleteWidget(w)
        }
    }

    // ...dozens of more methods with *exact* same catch block
}

Or you can also intercept each method call on WidgetDao by overriding invokeMethod method on its metaClass and handle exception (try/catch). Similar to this.

查看更多
登录 后发表回答