Skip to content
Print

Thoughts on jPersist

15
Nov
2007

Disclaimer: For those of you who don’t know, my pet project is an ORM based on the active record pattern (ActiveObjects).  As such, my opinions are probably colored somewhat.  Take everything I say here with a grain of salt.

There seems to have been a recent resurgence of interest in Java implementations of the active record pattern in recent months.  Most traditional Java ORMs (like Hibernate/JPA) implement the data mapper pattern, as it is far easier to apply to a static language like Java.  Yet I can count a number of new (at least to me) ORM projects which attempt to fill this void.  One such project is jPersist.  From the project page:

jPersist is an extremely powerful object-relational persistence API that is based on the Active-Record pattern. jPersist is mapless and has no need for XML or annotation based mapping (all mapping is automatic and dynamic).

Sounds promising!  I’m always in favor of any framework which can reduce the boiler-plate configuration required, especially when the configuration would have been in a language as verbose as XML.  But irregardless of the method for configuration, I’m always interested in how alternative frameworks implement the active record pattern.  As they say, inspiration is one part perspiration and three parts plagiarism.

So I started to dig through the project page a bit, trying to find more info.  Unfortunately, the jPersist project page is a bit weird in how the whole thing is structured.  The page layout implies that jPersist is in fact a sub-project of some kind, which lead me to initially discount the “Documentation” link in the main nav bar.  Even after I found the documentation though, I was somewhat disappointed in its limited scope.  Effectively, the only documentation available is some basic javadoc and a “getting started” tutorial.  That’s alright though, I can work with that.  Code samples are more informative anyway, right?  I downloaded the full distribution (including javadoc and examples) and began to poke around.

The first thing I noticed upon opening the “DatabaseExample.java” file was the syntax: it’s very verbose.  Granted, most persistence APIs suffer from a less-than-DSL design, but I was still a bit taken aback at the volume of code required to accomplish a simple task.  For example, this is how you INSERT a new entity “Contact” with jPersist:

Database db = dbm.getDatabase();
db.saveObject(new Contact("alincoln", "mypasswd1", "Abraham", "Lincoln", 
        null, "alincoln@unitedstates.gov"));

This is assuming that you have defined the POJO Contact with a constructor taking all of the above arguments.  Obviously this could have been just as easily simplified into something more like this:

Contact c = new Contact();
c.setContactId("alincoln");
c.setPassword("mypasswd1");
c.setFirstName("Abraham");
c.setLastName("Lincoln");
c.setEmail("alincoln@unitedstates.gov");
 
Database db = dbm.getDatabase();
db.saveObject(c);

Still a bit verbose, but understandably so. I don’t know of any persistence API in Java that can accomplish the same thing more compactly, so I won’t hold it against jPersist. 

What really stands out at me in this example is that Contact isn’t actually a database peer, it’s a bean.  It’s just a regular, run-of-the-mill POJO created using a constructor upon which mutators are invoked.  This doesn’t really seem significant until you consider the claim from the project page (emphasis mine):

jPersist is an extremely powerful object-relational persistence API that is based on the Active-Record pattern.

Hmm, that’s odd, because it sure looks like data mapping to me.  By definition, the active record pattern requires the entities to directly peer to database rows or (more correctly) result-set rows.  You can’t just instantiate an active record entity, it must be created for you since it has to peer to the database somehow.  More importantly, to satisfy the active record pattern, entities must have the ability to persist themselves, at least from an API standpoint.  In this example, we have to haul around an instance of Database which we invoke separately to create, update, delete and query our entities.  This property is the hallmark of the data mapper pattern, which (as the name implies) involves a separate mapper which translates data from one form (entity beans) to another (database records).

Upon digging a bit further, I did manage to find “ProxyExample.java”.  The title itself seemed promising as any implementation of the active-record pattern in Java must utilize proxies at some level (JDK interface proxies or otherwise).  Digging into the source for the example, I discovered an interface Contacts extending DatabaseObject which was used further down in the following way:

Database db = dbm.getDatabase();
Contacts c = (Contacts) db.castDatabase(Contacts.class);
 
c.setResultSetConcurrency(ResultSet.CONCUR_UPDATABLE);
c.executeQuery("select * from contacts where 1 = 0");
 
c.moveToInsertRow();
c.setContactId("contactId" + System.currentTimeMillis());
c.setPassword("password");
c.setFirstName("First Name");
c.setLastName("Last Name");
c.setCompanyName("Company Name");
c.setEmail("email");
c.insertRow();

So it does seem that the active-record pattern is supported as a secondary mechanism for persistence (the documentation heavily emphasizes the data mapper style).  I do find it a bit odd though that we’re executing queries against an entity directly, cursoring around in result sets and still performing operations with a non-peered entity instance.  It’s also a bad sign that even having the documentation in front of me, as well as a pretty solid knowledge of database concepts, I’m still not entirely sure what the above code does on a semantic level.

Incidentally, if you look at the javadoc for DatabaseObject, it is basically functioning as a super-interface for any persistence class.  Database is the most notable implementation.  Thus, technically speaking we’re still not getting the active-record pattern in the above sample, we’re just being handed a data mapper which maps data from itself to the database.  You could make an argument that this satisfies the basic properties of active record, but I’m skeptical.

Along this line, I’d like to point out that the API of DatabaseObject (and by extension, Database) is heavily dependant on modification of its internal state.  For example, notice anything odd about the following snippet?

Database db = dbm.getDatabase();
db.queryObject(new Contact(), 
        "where :companyName = 'United States' order by :lastName");
 
Contact contact = null;
while (db.hasNext() && db.next() != null) {
    db.loadObject(contact = new Contact());
    System.out.println(contact);
}

Passing over the introduction of yet another framework-specific query language, notice the way the calls are structured?  Database itself is being used as an iterator.  So in a nutshell, you query the database using the queryObject(Object, String) method, which opens a result-set and saves it internally.  You then iterate over the database, loading the current object as you go.  If you want to be academic about this, what we have here is called an “internal iterator”.  As any compsci 201 student will tell you, internal iterators are bad news, both for concurrency and scalability.  Also, they tend to somewhat unintuitive APIs (iterating over a database?) and non-standard idioms.  In addition to all, this approach also imposes a hard limit on the number of queries which can be inspected at once against a given Database instance (one).  This leads to more odd idioms (like maintaining n Database instances for flexibility) and can introduce some bugs which would be very difficult to track down.

Moving on through the examples, a few more things jumped out at more, both positive and negative.  As I mentioned above, jPersist introduces its own SQL-derivative query language which allows querying for entities directly using field names (something supported by Hibernate using HQL but not by ActiveRecord or ActiveObjects).  Consider the following jPersist example:

Database db = dbm.getDatabase();
db.queryObject(new Contact(), 
        "where :companyName = 'United States' order by :lastName");

Compare to the corresponding ActiveObjects code:

EntityManager em = ...
Contact[] contacts = em.query(Contact.class, 
        Query.select().where("companyName = 'United States'").order("lastName"));

Hmm, which do you think is more readable? (hint: it ain’t ActiveObjects)

There are varying schools of thought on whether framework-specific query languages are a good idea or not.  Personally, I’m very opposed to them due to the added complexity and overhead they impose.  Why would I want to learn n different query languages rather than sticking with good old SQL?  On the flip side, I can see why such “spin-off” languages are nice when I look at examples like the above.  It’s really a matter of personal preference.

Another thing that’s really worth mentioning is the design decision made by jPersist not to avail itself of Java 5 syntax.  For example, if you want to use prepared statement parameters with a jPersist query, you must pass them in the following way:

db.queryObject(customer, "where :state = ? order by :lastName", 
        new Object[] {"arizona"});

A basic application of varargs would have simplified this API tremendously. Another example of the lack of Java 5 usage is in the active-record sample:

Contacts c = (Contacts) db.castDatabase(Contacts.class);

Notice the cast? Adding a type parameter to the castDatabase method would eliminate the cast entirely without bulking up the method call in any way.

The major advantage to not using Java 5 features is compatibility.  You can use jPersist on pre-Java 5 systems, possibly even back as far as Java 1.2 (not sure if it uses assertions or not).  Though, this advantage is of questionable value given the scarcity of such neolithic JVMs.

There’s more that’s worth mentioning, like the rather odd syntax for defining relations or the all-important schema generation, but this post is already pushing record sizes.  In brief: jPersist exhibits some interesting properties, and it certain provides a unique perspective on the field of database persistence, but I can’t say I’m particularly fond of the API.  Hopefully, the weaknesses I’ve enumerated will eventually be rectified, resulting in a really excellent library.

Comments

  1. Hi Daniel,

    This is along the lines of the two dzone readers who down voted my article because they we friends of yours. Of course everyone shot me down for complaining, but the reality is that it’s not cool (along the same line as sportsmanship and being polite), and I would not do the same to you.

    I have a few corrections for you:

    o The passing items via a constructor or calling several setters is a matter of preference (I prefer constructors and less lines of code), but this is an example not real world.
    o You missed the part about extending PersistentObject, which allows jPersist to track an object to a row in the database, as well as, tracking the state of persistence.
    o With jPersist loading and inserting makes an object persistent (providing it extends PersistentObject), and this ties an object to a row in the database.
    o I chose this implementation because I wanted to be able to work with POJOS, as well as, persistent objects.
    o It’s also possible to extend jpersist.Database, in which case you are highly coupled to the database (I don’t document that).
    o The internal iterator is simply a wrapper around a JDBC ResultSet that allows you to traverse the database (if you consider ResultSet an internal iterator).
    o jpersist.Database wraps Connection, Statement and ResultSet functionality. The jpersist.Database also has a clone() method which keeps the connection but uses new Statement and ResultSet objects. This allows you to perform multiple queries with the same connection, so you’re not just limited to one query.
    o I did not implement an SQL derivative. It is not a framework-specific query language. The only thing going on there is with “:attribute” which is replaced with the column name; the where clause is then added to the SQL statement being built and passed to a prepared statement.
    o Yes I did want to support Java 1.4, because I believe there are still a lot of Java 4 users, and I am working on a Java 5+ version.
    o If I am avoiding XML and annotations, does it not make sense that I would have a different scheme for handling associations?

    David Bulmore Thursday, November 15, 2007 at 12:29 pm
  2. Hi Daniel,

    I came across jPersist very recently. From their example everything look nice and easy. But I when I tried to map tables with name different from the classes (using the interfaces TableMapping and ColumnMapping) I could’nt figure out a way to make it run properly.
    I was wondering if you were still playing with it or not?

    By the way, carry on with the scala series…very interesting.

    Olivier

    Olivier Sunday, February 3, 2008 at 1:18 am
  3. Sorry, Olivier, but I haven’t really touched it since I wrote the article. I suggest you contact the originator, David Bulmore (see preceding comment) for more assistance.

    Daniel Spiewak Sunday, February 3, 2008 at 1:56 am

Post a Comment

Comments are automatically formatted. Markup are either stripped or will cause large blocks of text to be eaten, depending on the phase of the moon. Code snippets should be wrapped in <pre>...</pre> tags. Indentation within pre tags will be preserved, and most instances of "<" and ">" will work without a problem.

Please note that first-time commenters are moderated, so don't panic if your comment doesn't appear immediately.

*
*