I recently established a new open source project http://sourceforge.net/projects/kauklahti/

Nowadays, JPA and Hibernate is the object-relational mapping standard. So it is quite stupid to write your own solution, right?

Well, we’ve been using Hibernate several years in different kinds of projects. We’ve seen solutions and problems from other vendors as well. Common problem is that complex class hierachies with many tables easily cause performance problems.

Inexperienced coders don’t check the actual SQL and only trust table generation tools. Even with best coders, we spend a lot of time with tuning fetching strategies and caching solutions. And then we might switch to custom SQL and JDBC in most complex queries. When this is done carefully, we get things right in the end.

In my opinion, this tuning and configuring takes too much time. I am not happy with the productivity of current JPA tools.

Furthermore, there are a lot of other “minor” problems. Lazy initializations and library-specific Collections are problems for a remote client and Swing applications. There are lot of library dependencies and we need exactly the correct versions (yes, there is Maven/Ivy, but still conflicts with application server classpath and other frameworks might cause a major headache). And I don’t like writing xml or annotations that make your code messy.

I wanted a simpler solution. I looked at couple of alternatives, but APIs weren’t exactly what I was looking for.

However, Spring framework has this simple class JdbcTemplate. It’s great with plain JDBC. Spring also includes BeanPropertyRowMapper that extracts ResultSet into list of JavaBeans. I liked the idea, but I also wanted some support for joined tables and full CRUD generation. I wrote Kauklahti to do just that.

How does it work? Supposing we have tables:

create table guitar (
  id INTEGER PRIMARY KEY,
  name varchar(100));

create table guitarstring (
  id INTEGER PRIMARY KEY,
  tone varchar(1),
  guitar_id INTEGER);

alter table guitarstring add constraint string_guitar_id
  foreign key (guitar_id) references guitar (id);

We write Java classes:

public class Guitar {

  private Long id;
  private String name;
  private List<GuitarString> strings;

  public Guitar() {}

  public Guitar(Long id, String name, List<GuitarString> strings) {
    this.id = id;
    this.name = name;
    this.strings = strings;
  }
}

public class GuitarString {

  private Long id;
  private String tone;

  public GuitarString() { }

  public GuitarString(Long id, String tone) {
    this.id = id;
    this.tone = tone;
  }
}

Then we create table mapping:

Table guitarTable = new Table(Guitar.class, "GUITAR");
Column[] guitarCols = {
  new Column("id", "id", true),
  new Column("name", "name", false)
};
guitarTable.setColumns(guitarCols);

Table stringTable = new Table(GuitarString.class, "GUITARSTRING");
Column[] stringCols = {
  new Column("id", "id", true),
  new Column("tone", "tone", false)
};
stringTable.setColumns(stringCols);

Join stringJoin = new ChildRefJoin("strings", stringTable,
  new String[] {"id"},
  new String[] {"guitar_id"});
guitarTable.setJoins(new Join[] {stringJoin});

Or if you like convention over configuration, you may use AutoConfigurator to create Table-mappings:

AutoConfigurator autoConf = new AutoConfigurator("fi.devtrain.*");
Table table = autoConf.config(Guitar.class);

Now it’s simple to generate SQL:

GuitarString aString = new GuitarString(new Long(1), "A");
List<GuitarString> strings = new ArrayList<GuitarString>();
strings.add(aString);
Guitar guitar = new Guitar(new Long(1), "Strato", strings);
List<WriterResult> inserts = mapper.writeInsert(guitar,guitarTable);
List<WriterResult> updates = mapper.writeUpdate(guitar,guitarTable);
List<WriterResult> deletes = mapper.writeDelete(guitar,guitarTable);

Execute it with Spring JdbcTemplate:

JdbcTemplate jdbcTemplate = new JdbcTemplate(myDataSource);
for (WriterResult wr : inserts) {
    jdbcTemplate.update(wr.getSql(), wr.getParams());
}

For queries, use Spring ResultSetExtractor with Kauklahti mapper.

ResultSetExtractor extr = new ResultSetExtractor() {
  public Object extractData(ResultSet resultSet)
         throws SQLException, DataAccessException {
    return mapper.extract(resultSet, guitarTable);
  }
};
String query = mapper.writeSelect(guitarTable);
List guitars = (List) jdbcTemplate.query(query, new Object[0],extr);

So what’s so great about Kauklahti? I wrote the solution, because it only took about 1300 LOC. And because:

  • Mapping API is simple and programmatic
  • Every piece of SQL is in my hands before execution
  • It provides basic features I need in ORM (and nothing more)
  • Only log4j.jar is required library dependency (even Spring is optional)

If you’re interested, download latest release from SourceForge or check out the code from http://kauklahti.svn.sourceforge.net/svnroot/kauklahti

User’s Guide and test examples are included to get things started.