Friday, November 16, 2007

Code generation for fun and profit, Part I

Problem statement

Let’s say you need to sort a bunch of beans in your enterprise application.

Now, first of all and by all means, try to use the underlying database. Database management systems are written and highly optimized for data retrieval and ordering. In pure SQL, ordering is as easy as appending ORDER BY at the end of your SQL statement, and you should only invest some time into considering how to define columns and their direction programmatically. ORM solutions, like Hibernate, make the job even easier with Criteria queries and the like.

But, sometimes you really need to sort some data in memory, before you hand it over to the database. Typical example of this scenario is integration or data import with some other, legacy, system. Of course, Java has a Collections.sort() method, which, in case of non-Comparable entities, requires an implementation of Comparator interface. Its compare() method is used to define ordering of beans in a collection.

Typical comparator implementation, handling some example TestBean, might look something like this:
public class TestBean {
private Integer i;
private String s;
private Date d;

}

public class ExampleComparator implements Comparator {
// I, S, D
public int compare(Object o1, Object o2) {
TestBean b1 = (TestBean)o1;
TestBean b2 = (TestBean)o2;

int c1 = ComparatorHelper.compare(b1.getI(), b2.getI());
if (c1 != 0) return c1;

int c2 = ComparatorHelper.compare(b1.getS(), b2.getD());
if (c2 != 0) return -c2; // descending order

return ComparatorHelper.compare(b1.getD(), b2.getD());
}
}
Here the common comparing functionality has been extracted into a utility method:
public final class ComparatorHelper {
private ComparatorHelper() {}

public static int compare(Comparable x, Comparable y) {
if (x == y) {
return 0;
}
else if (x == null) {
return Integer.MIN_VALUE;
}
else if (y == null) {
return Integer.MAX_VALUE;
}
else {
return x.compareTo(y);
}
}
}
First problem with this approach is when you have several different classes to sort. Furthermore, you might want only particular columns, and in different orders, for each of those classes, to be considered in sorting process. And that should somehow be programmatically determined, rather than being hard-coded.

All of the above would necessitate having to write separate Comparator classes for each and every combination. While you may think that writing a generic comparator with bunch of ifs or such might do the trick, at least for a single class, there is still a performance issue, since compare() method will be invoked extensively in a sorting algorithm.

Enter code generation

Ideally, we would generate our Comparator implementation, according to the desired parameters, on-the-fly. Something like this would be nice:

Comparator<Testbean> c1 = ComparatorFactory.createComparator(TestBean.class,
new String[] { "i", "s", "d" },
new Class[] { Integer.class, String.class, Date.class },
new int[] { 1, -1, 1 });
Meaning of the above should be self-explanatory, but just in case: it is expected that the above method creates a comparator for TestBean class, where properties i, s and d are compared in that order, and s property will be descending. The above argument format is, truth be told, very impractical for interfacing with other parts of the system. Better approach would be using a method chaining parameter class, something like this:

Comparator<Testbean> c1 = ComparatorFactory.forClass(TestBean.class)
.addProperty(“i”, Integer.class)
.addProperty(“s”, String.class, false)
.addProperty(“d”, Date.class)
.generate();
But I will be leaving that as an exercise for junior developers… Nah, I’ll just do it later; I really like those fluent interfaces.

Now back to the code generation bit. The algorithm for a comparator is pretty straight-forward: for each property, compare values using ComparatorHelper. If returned value is non-zero, return it, possibly calculating in the descending order. Otherwise, compare the next property.

This post is getting quite long by now… so I have to say goodbye for now. Stay tuned for sequel where I’ll be using the CGLIB library, and will be providing actual code.

Wednesday, October 24, 2007

Stupid Java superclass constructors


Apparently, constructors in Java suck. Consider a following example:

public class Page {
protected int page;
protected int pageSize;
protected List result;

public Page(int page, int pageSize) {
this.page = page;
this.pageSize = pageSize;
findResult();
}

protected void findResult() {
// do something with page & pageSize
result = doQuery(…, page, pageSize);
}

public List getResult() {
return result;
}
}

Now you want to introduce a subclass which contains different implementation of findResult(). But, let’s also say you decide you want to use an additional parameter.

public class OrderedPage {

protected int sortColumn;

public OrderedPage(int page, int pageSize, int sortColumn) {
super(page, pageSize);
this.sortColumn = sortColumn;
}

@Override
protected void findResult() {
// do something with page & pageSize & sortColumn

}

}

Well, the problem is that sortColumn field in the above class will be uninitialized when findResult() methods is invoked.

If you’re pressed for time and able to change the base class, you can add a protected, no-arg constructor, and repeat the whole initialization and the method call of findResult() in the OrderedPage class again. The cleanest approach would involve rewriting all the public getters, like getResult() according to lazy-loading approach, and remove the invocation from the base class constructor. Like this:


public List getResult() {
if (result == null) {
result = findResult();
}
return result;
}

However, you might have a situation where there are multiple getters to change. Altering them, apart from being a tedious job, might involve slight semantic changes to a class eg. a variable declared final will have to be “unfinalized”.

And, let’s not forget, you might not actually be able to change the base class.

There is, of course, a hack. It consists of using a static method and ThreadLocal variable:

public class OrderedPage {

private static final ThreadLocal<Integer> threadSortColumn =
new ThreadLocal<Integer>();


private static int hack(int pageSize, int sortColumn) {
threadSortColumn.set(Integer.valueOf(sortColumn));
return pageSize;
}

protected int sortColumn;

public OrderedPage(int page, int pageSize, int sortColumn) {
super(page, hack(pageSize, sortColumn));
}

@Override
protected void findResult() {
// do something with page & pageSize & sortColumn
sortColumn = threadSortColumn.get().intValue();

}

}

Quite surprisingly, it doesn’t look that bad! And it will confuse the hell out of the junior developers, as well as senior wannabes.

Code tight!