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.
The annotation I have in mind would automatically wrap the contents of the annotated method with the whole 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.
wrap(int[] array, int offset, int length) The wrap() method wraps an int array into a buffer. The new buffer will be backed by the given int array; that is, modifications to the buffer will cause the array to be modified and vice versa. The new buffer's capacity will be array.
2. Re: try catch around annotated method. Right approach, but Seam doesn't support method level interceptors, only class level interceptors. So you can attach the interceptor at class level, and then mark the method with the same annotation, and only intercept those.
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).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With