Tuesday, October 06, 2009

Enhance Exceptions with Context

Don't you wish sometimes that Java had the feature for exceptions to automatically capture the values of the variables in the context that were present when an exception occurs? Well I guess we just have to do it manually. Let's see what it would look like:

public class SomeClass {
public void someMethod(String x) {
try {
int pos = x.indexOf("abc");
String y = x.susstring(pos);
} catch (RuntimeException e) {
throw new RuntimeException(
"there was a problem here, with param x="
+ x, e);
}
}
}

Ok, now whenever someone calls someMethod("noa-b-c"); they will get a friendly message in the exception telling them what the value of x was during the invocation. That wasn't too bad, but what if the method had 3 parameters? What if you didn't have the try block around the whole body and it still threw an exception?

There must be a better way? I don't want to always tell the computer how to do things, how come I can't just say what I want? I want to tell Java that when an exception happens in my method, it should capture the context and chain the original exception. I will just use an annotation to tell Java to do this for me.
public class SomeClass {
@ThrowsContext
public void someMethod(String x) {
int pos = x.indexOf("abc");
String y = x.substring(pos);
}
}

There, that is better! Um, wait, how is that going to work? Now I am going to have to make something that will process that annotation and put the try catch there and include the parameter values. I could run my code in some sort of container that I can proxy the object of SomeClass and in the proxy I can add this new feature, then I need to make sure that all my clients to this method go through the proxy, then oops, I need to use CGLIB because I didn't use an interface, man, that is goign to all be easy.

There must be a better way! AspectJ is still Java, let's see if that wil work. We can create a pointcut for methods that have the @ThrowsContext annotation, and after the method throws an exception, we will chain it with our exception with a message of the context and chain teh original exception.

public aspect ExceptionContext {
pointcut ctx(ThrowsContext t, Object th) :
execution(@ThrowsContext * *..*(..)) &&
@annotation(t) &&
this(th);

after(ThrowsContext t, Object th)
throwing(RuntimeException e) : ctx(t, th) {
Object[] args = thisJoinPoint.getArgs();
throw new RuntimeException("parameters: " +
Arrays.toString(args) + "\nthis=" +th, e);
}
}

That is pretty to the point, it says what I want to do which makes programming more productive and fun. Maybe you don't want the context to leak out of your components, but you need this information to support debugging durign development, you can use LTW Load Time Weaving supported by AspectJ to only add this aspect behavior during deployments that you decide should have it.

Next time we will enhance the context and provide options to which context to include.


And here is the annotation:
@Retention(value=RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ThrowsContext {
}

Wednesday, March 11, 2009

Refactor classes to be domain clean

The beauty of object oriented programming is that you can have a program that resembles the real world objects that it is to represent. Domain driven design is the notion that you create models based on a "domain". That is a subject area. This can be fuzzy, or it can be industry agreed upon. The catch is that you are writing an application, and not a domain model. What does that mean? It means that you will be tempted to add fields to your classes that meet your application's needs, but are not really part of your domain.
Transcendental Beans is here to save you from polluting your domain model with application schemata. You have the power of AspectJ introduction to separate application schema from domain schema.
Try aspect refactoring with AspectJ on your persistent classes with Transcendental Beans

Monday, March 09, 2009

Introduce JAXB to your POJOs

Suppose you want to keep your POJO really a POJO? If you use JPA annotations on a class, is it still really a POJO? A POJO should be usable as a domain object independent of whether it came from a database, or from a remote service. So If I see @Entity on your POJO, I know it is really a database object, and I start thinking all about it's dependencies, do I need a transaction, do I need a JDBC connection, what JAR has the JPA annotation, maybe it isn't in my JRE, no more a "plain" Java object.

Ok, but I want to store my POJO in a database, what do I do? Ok, that will be my next article... Today, what if I want to use JAXB to serialize the POJO as XML? Then I need to use @javax.xml.bind.annotation.XmlRootElement to annotate the class. That just ruined my POJO. AspectJ can add fields, methods, annotations, and parents to classes. Why not just introduce the JAXB annotations necessary to marshal the object at runtime just for the situation that I need?

Here is my POJO:
public class Order {
private String number;
private String product;
private String customerEmail;
private String customerName;
}


Now, here is the POJO with the JAXB annotation:
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class Order {
private String number;
private String product;
private String customerEmail;
private String customerName;
}


Isn't marshaling an object to XML a totally different concern from if an Order needs the customer's email address? So, let's separate those two concerns:

import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public aspect Jaxbify {
declare @type : Order : @XmlRootElement;
}

This aspect introduces the XmlRootElement annotation to the Order class, keeping Orders, Orders.
Next time I'll show how to run this example.

Labels