Java annotation for wrapping a method
To do this, you would need some AOP framework that would use a proxy around your method. This proxy would catch the exception and execute the finally block. 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.
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:
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.
EDIT: in case you want to return something from your methods, then make the logAndCleanup()
method generic. 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 :
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.
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
). Other way is to use AOP, say AspectJ or Spring AOP (If you use Spring).