简体   繁体   English

用于包装方法的 Java 注释

[英]Java annotation for wrapping a method

I have a lot of boilerplate code that basically follows this pattern:我有很多基本遵循这种模式的样板代码:

function doSomething() {
  try {
    [implementation]
    [implementation]
    [implementation]
    [implementation]
  } catch (Exception e) {
    MyEnv.getLogger().log(e);
  } finally {
    genericCleanUpMethod();
  }
}

I'd love to create my own annotation to clean my code up a bit:我很想创建我自己的注释来清理我的代码:

@TryCatchWithLoggingAndCleanUp
function doSomething() {
  [implementation]
  [implementation]
  [implementation]
  [implementation]
}

The method signatures vary wildly (depending on the actual implementation of the method), but the boilerplate try/catch/finally part is always the same.方法签名变化很大(取决于方法的实际实现),但样板文件 try/catch/finally 部分始终相同。

The annotation I have in mind would automatically wrap the contents of the annotated method with the whole try...catch...finally hoopla.我想到的注释会自动用整个try...catch...finally hoopla 包装带注释方法的内容。

I've searched high and low for a straightforward way to do this, but have found nothing.我一直在寻找一种简单的方法来做到这一点,但一无所获。 I don't know, maybe I just can't see the woods for all the annotated trees.我不知道,也许我只是看不到所有带注释的树木的树林。

Any pointers on how I might implement such an annotation would be greatly appreciated.任何关于我如何实现这样一个注释的指针将不胜感激。

To do this, you would need some AOP framework that would use a proxy around your method.要做到这一点,您需要一些 AOP 框架来在您的方法周围使用代理。 This proxy would catch the exception and execute the finally block.该代理将捕获异常并执行 finally 块。 Quite frankly, if you don't use a framework supporting AOP already, I'm not sure I would use one just to save these few lines od code.坦率地说,如果您还没有使用支持 AOP 的框架,我不确定我是否会使用一个来保存这几行代码。

You could use the following pattern to do this in a more elegant way, though:不过,您可以使用以下模式以更优雅的方式执行此操作:

public void doSomething() {
    logAndCleanup(new Callable<Void>() {
        public Void call() throws Exception {
            implementationOfDoSomething();
            return null;
        }
    });
}

private void logAndCleanup(Callable<Void> callable) {
    try {
        callable.call();
    } 
    catch (Exception e) {
        MyEnv.getLogger().log(e);
    } 
    finally {
        genericCleanUpMethod();
    }
}

I just used Callable<Void> as an interface, but you could define your own Command interface:我只是使用Callable<Void>作为接口,但您可以定义自己的Command接口:

public interface Command {
    public void execute() throws Exception;
}

and thus avoid the need to use a generic Callable<Void> and return null from the Callable.从而避免使用通用Callable<Void>并从 Callable 返回 null 的需要。

EDIT: in case you want to return something from your methods, then make the logAndCleanup() method generic.编辑:如果你想从你的方法中返回一些东西,那么让logAndCleanup()方法通用。 Here's a complete example:这是一个完整的例子:

public class ExceptionHandling {
    public String doSomething(final boolean throwException) {
        return logAndCleanup(new Callable<String>() {
            public String call() throws Exception {
                if (throwException) {
                    throw new Exception("you asked for it");
                }
                return "hello";
            }
        });
    }

    public Integer doSomethingElse() {
        return logAndCleanup(new Callable<Integer>() {
            public Integer call() throws Exception {
                return 42;
            }
        });
    }

    private <T> T logAndCleanup(Callable<T> callable) {
        try {
            return callable.call();
        }
        catch (Exception e) {
            System.out.println("An exception has been thrown: " + e);
            throw new RuntimeException(e); // or return null, or whatever you want
        }
        finally {
            System.out.println("doing some cleanup...");
        }
    }

    public static void main(String[] args) {
        ExceptionHandling eh = new ExceptionHandling();

        System.out.println(eh.doSomething(false));
        System.out.println(eh.doSomethingElse());
        System.out.println(eh.doSomething(true));
    }
}

EDIT : And with Java 8, the wrapped code can be a bit prettier :编辑:使用 Java 8,包装的代码可以更漂亮一点:

public String doSomething(final boolean throwException) {
    return logAndCleanup(() -> {                
        if (throwException) {
            throw new Exception("you asked for it");
        }
        return "hello";                
    });
}

You could use dynamic proxies to implement this.您可以使用动态代理来实现这一点。 It takes a bit of setting up, but once done, is pretty straightforward.这需要一些设置,但一旦完成,就非常简单了。

First, you define an interface and place the annotation on the interface.首先,您定义一个接口并将注释放置在该接口上。

public interface MyInterface {
    @TryCatchWithLogging
    public void doSomething();
}

Now, when you want to provide an implementation of the interface to a consumer, dont provide with him with the actual implementation, but instead a Proxy to it.现在,当您想向消费者提供接口的实现时,不要向他提供实际的实现,而是向它提供代理。

MyInterface impl = new java.lang.reflect.Proxy.newProxyInstance(
                         Impl.class.getClassLoader(), 
                         Impl.class.getInterfaces(), YourProxy(new Impl());

Then implement YourProxy.然后实现YourProxy。

public class YourProxy implements InvocationHandler {
....

     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
         if ( method.isAnnotationPresent(TryCatchLogging.class) ) {
              // Enclose with try catch
}

you can implement annotation and annotation processor yourself and instrument code everytime when you do compilation ( javac -processor ).您可以自己实现注释和注释处理器,并在每次编译时检测代码( javac -processor )。 Other way is to use AOP, say AspectJ or Spring AOP (If you use Spring).另一种方法是使用 AOP,比如 AspectJ 或 Spring AOP(如果你使用 Spring)。

Another way is using javassist processing class file after building, your need searching methods with specified annotation in your classes.另一种方法是在构建后使用javassist处理类文件,您需要在类中搜索具有指定注释的方法。 And add bridge methods for calling between wrapped method and original method.并添加用于在包装方法和原始方法之间调用的桥接方法。 It look like, calling bridgeMethod() -> wrapperMethod() -> originalMethod() .看起来,调用bridgeMethod() -> wrapperMethod() -> originalMethod() I make a simple project for implementing that approach.我做了一个简单的项目来实现这种方法。 Your can reference from https://github.com/eshizhan/funcwraps .您可以参考https://github.com/eshizhan/funcwraps

afaik you would have to monitor each method call for the @TryCatchWithLoggingAndCleanUp annotation, which would be very tedious. afaik 您必须监视@TryCatchWithLoggingAndCleanUp注释的每个方法调用,这将非常乏味。 basically you could get each methods annotations by reflection and then do your exception handling and logging.基本上你可以通过反射获得每个方法的注释,然后进行异常处理和日志记录。 but im not sure you would want to do that.但我不确定你是否愿意这样做。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM