[英]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.