Skip to content

An Easier Java ORM: Indexing

6
Aug
2007

In continuing with my series on ActiveObjects, this post delves into the eternal mysteries of search indexing and Lucene integration. Most modern web applications not only store data in a database, but also in an index of some kind to allow fast and efficient searching. Java’s Lucene framework provides an excellent mechanism for this functionality, however it can be somewhat cryptic and hard to use. To ease this pain, ActiveObjects provides auto-magical Lucene integration for specified fields, making it trivial to index and search for entities.

Unless there is great public outcry, I intend this to be the last of my “Easier Java ORM” series (with the exception a roundup post for linking purposes). As fun as it is being self-promoting and pushing my favorite open source project, I feel a slight twinge of guilt every time I flood your feed agregator with more information on a library in which you may or may not have interest. I’ll probably still post about ActiveObjects from time to time, but only on occasions when there is something of special note.

Indexing

Of course, we can’t even begin to talk about searching for entities unless there is some data from the entity added to the index. The actual creation and maintenance of the index is usually considered the hardest part of working with Lucene. In ActiveObjects, it requires two separate steps.

Firstly, you must decide which fields and which entities you wish to index. Let’s say that we have a simple blog schema as follows:

public interface UserModifiedEntity extends SaveableEntity {
    @Default("CURRENT_TIMESTAMP")
    public Calendar getDate();
    @Default("CURRENT_TIMESTAMP")
    public void setDate(Calendar calendar);
 
    @Default("false")
    public boolean isDeleted();
    @Default("false")
    public void setDeleted(boolean deleted);
}
 
public interface Post extends UserModifiedEntity {
    public String getTitle();
    public void setTitle(String title);
 
    @SQLType(Types.CLOB)
    public String getText();
    @SQLType(Types.CLOB)
    public void setText(String text);
 
    @OneToMany
    public Comment[] getComments();
}
 
public interface Comment extends UserModifiedEntity {
    public Post getPost();
    public void setPost(Post post);
 
    public String getCommenter();
    public void setCommenter(String name);
 
    @SQLType(Types.CLOB)
    public String getText();
    @SQLType(Types.CLOB)
    public void setText(String text);
}

In this schema, we have both Post and Comment entities. Both entity types extend UserModifiedEntity, which contains some fields which will be common to both resulting tables. Both Comment and Post also have “text” fields, containing the actual meat of each entity’s value.

Now, for our blog’s search engine, we’re going to want to do something a bit more precise than search for all values contained in any entities. Actually, at this point, ActiveObjects wouldn’t index any values whatsoever. We need to tag the fields we want to add to the index with the @Indexed annotation. Let’s assume that we don’t need to search on comments at all, just posts. The modified Post entity might look something like this:

public interface Post extends UserModifiedEntity {
    @Index
    public String getTitle();
    @Index
    public void setTitle(String title);
 
    @Index
    @SQLType(Types.CLOB)
    public String getText();
 
    @Index
    @SQLType(Types.CLOB)
    public void setText(String text);
 
    @OneToMany
    public Comment[] getComments();
}

That takes care of step one in the indexing procedure. ActiveObjects now has everything it needs to know relating to what it should index. Now we need to inform it to actually perform the indexing, and where to store the result. This is all handled using a special EntityManager subclass: IndexingEntityManager.

// ...
IndexingEntityManager manager = new IndexingEntityManager(jdbcURI, username, password, 
        FSDirectory.getDirectory("~/lucene_index"));
 
Post post = manager.create(Post.class);
post.setTitle("My Cool Post");
post.setText("Here's some test text that I'll use to test the search indexing.  "
        + "It's really amazing what you can do with so little code...");
post.save();

As you can see, we’re using an instance of IndexingEntityManager to access and create all of our entity instances (all one of them). This is all that is necessary to cause ActiveObjects to handle the indexing for these entities.

Oh, FSDirectory is actually a Lucene class (sub-classing Directory) which is used to tell the Lucene backend where to store the index. Since we’re actually using the Lucene Directory abstraction classes, the index could just as easily be stored in memory, or even in another database.

Searching

Obviously, an index isn’t all that useful if you can’t do anything with it. Since our goal from the start was to provide search capabilities to our rather limited blog, we need to have a way of accessing the Lucene indexing and performing a search. Again, ActiveObjects makes this incredibly easy:

// ...code from above
Post[] results = manager.search(Post.class, "test search terms");
 
System.out.println("Search results:");
for (Post post : results) {
    System.out.println("   " + post.getTitle());
}

The search method delegates its call down to the Lucene engine, which parses the search terms and runs through the index searching for any key-value sets (or Document(s), as Lucene refers to them) which match in the “title” or “text” fields. By default, ActiveObjects runs the search against all index fields in the specified entity type. Since this is usually the behavior people want when using Lucene, it is a sane default.

If the mindless defaults aren’t good enough for your application, you are quite free to use the Lucene index directly. IndexingEntityManager provides accessors for the Directory containing the index, as well as the Analyzer in use. (getIndexDir() and getAnalyzer()) Of course, you can also extend IndexingEntityManager and provide your own search() implementation.

Removing from the Index

Almost as important as adding entities to an index is removing them. We don’t want our searches to pull back deleted posts. IndexingEntityManager can handle this task for us automatically, to a point. The problem is that in our case, we’re not actually deleting the posts as such. We’re simply setting a flag in the row which indicates the post is deleted. We’re supplying all of the logic (theoretically) to ignore deleted posts and comments.

If we were using the EntityManager#delete(Entity…) method, we would be DELETEing the rows properly and then IndexingEntityManager could automatically remove the relevant Document(s) from the index. However, since we’re not doing this, we need a bit more logic. For simplicity’s sake, we’re going to put this logic into a defined implementation for the UserEditableEntity interface:

@Implementation(UserEditableEntityImpl.class)
public interface UserEditableEntity extends SaveableEntity {
    // ...
}
 
public class UserEditableEntityImpl {
    private UserEditableEntity entity;
 
    public UserEditableEntityImpl(UserEditableEntity entity) {
        this.entity = entity;
    }
 
    public void setDeleted(boolean deleted) {
        if (deleted && !entity.isDeleted()) {
            // deleting the entity, remove it from index
            ((IndexingEntityManager) entity.getEntityManager()).removeFromIndex(entity);
        } else if (!deleted && entity.isDeleted()) {
            // we're un-deleting the entity here
            ((IndexingEntityManager) entity.getEntityManager()).addToIndex(entity);
        }
 
         entity.setDeleted(deleted);
    }
}

Now, whenever we call setDeleted(boolean) on a Post or Comment instance, it will be removed from the index (if we’re deleting the entity), or re-added to the index (if we’re un-deleting it). In the case of Comment, it has no @Indexed methods, so IndexingEntityManager will more or less ignore the call to addToIndex(Entity) (it actually will iterate through all of the methods to find any @Indexed).

Related Content

Many sites have need of a “related content” algorithm. This is most often seen in blogs which show a list of “related posts”. Since ActiveObjects auto-magically handles indexing and searching, it only makes sense that it provide some mechanism for accessing related entities based on their indexed values. This is handled using the RelatedEntity super-interface.

Let’s assume that we want to be able to find related posts to a given Post instance. The only thing we need to do is make sure that the Post interface also extends RelatedEntity:

public interface Post extends UserEditableEntity, RelatedEntity<Post> {
    // ...
}

Now we can call:

Post post = // ...
Post[] related = post.getRelated();
 
System.out.println("Posts related to " + post.getTitle() + ":");
for (Post relate : related) {
    System.out.println("   " + relate.getTitle());
}

Alright, caveat time… First off, this does depend on the Lucene Queries contrib library, specifically the MoreLikeThis class. Secondly, I’m not entirely sure that this is working right. :-) I’ve yet to actually get it to return any related values whatsoever in my test bed. This could be due to the way I’m indexing, or possibly the way I’m using MoreLikeThis; I’m not sure. If it works for you, let me know! Also, if you have any experience with the MoreLikeThis functionality, I’d appreciate any pointers you may have.

Well, that about sums it up for indexing in ActiveObjects. Hopefully, this simplifies your data backend code still some more and eases your pain in dealing with Lucene.

An Easier Java ORM: Relations

31
Jul
2007

Per request in a comment on the previous article, I’ve decided to devote this post to the subject of relations and how they work in ActiveObjects.

There are two types of relations in database design: one-to-many and many-to-many. In a one-to-many relation, multiple rows in one table usually have a reference to a single row in another table (or quite possibly the same table, depending on the design). As a simple example, assume with me that all tapeworms reproduce solely asexually (which isn’t exactly true, but that’s beside the point). Thus, a single tapeworm would have dozens of offspring. The proud parent tapeworm would have a one-to-many relation to its children (if you could refer to them as such). Another, less parasitic example would be people living in a city. The city would have a one-to-many relation to the thousands of people living within its borders.

One-to-many relations are expressed in ActiveObjects about as simply as the concept can be expressed in words:

public interface City extends Entity {
    public String getName();
    public void setName(String name);
 
    @OneToMany
    public Person[] getOccupants();
}
 
public interface Person extends Entity {
    public String getFirstName();
    public void setFirstName(String firstName);
 
    public String getLastName();
    public void setLastName(String lastName);
 
    public City getCity();
    public void setCity(City city);
}

The “people” table (assuming we’re using the pluralizing name converter) would contain fields “id”, “firstName”, “lastName”, and “cityID”, with a foreign key constraint on cityID ensuring it matches an existing “cities.id” value. The “cities” table would only contain “id” and “name” fields.

The real magic occurs when the dynamic proxy handler attempts to field a call to the getOccupants() method. One of the first thing the method does (after checking for a defined implementation) is look for a relation tagging annotation. In this case, it finds @OneToMany. The handler then looks at the return type for the method, extracts the table name for the Person entity class, and constructs a query to return any people which have a cityID equaling the appropriate id.

If there were more than one field in Person which returned a City, each field would be checked for the relation. Thus, minimally the SQL executed would look like this:

SELECT DISTINCT OUTER.ID FROM (SELECT ID FROM people WHERE cityID = ?) OUTER

The outer/inner query construct is used to allow the UNIONing of multiple SELECT results corresponding with different fields in the people table. With a trivial sub-query like the one given, most database engines will optimize the SQL down to a single, highly performant query.

Many-To-Many

Many-to-many relations are even cooler than one-to-many(s). This is where you begin to see complex mappings such as the (usually standard) two-parent to many children relations in families. Another example might be user permissions. There are several user permission types, each of which could map to an arbitrary number of users. A straight one-to-many mapping doesn’t work here, since neither “end” of the relation refers to a single entity. Thus, we have a many-to-many relation.

In database design, many-to-many relations are almost always expressed using an intermediary table. Thus, if we were to map authors to books (allowing for co-authorships), we would have to create a design with three tables: authors, books and authorships, which solely handles the mapping between author and book. Here’s how this would look in ActiveObjects:

public interface Author extends Entity {
    public String getName();
    public void setName(String name);
 
    @ManyToMany(Authorship.class)
    public Book[] getBooks();
}
 
public interface Authorship extends Entity {
    public Author getAuthor();
    public void setAuthor(Author author);
 
    public Book getBook();
    public void setBook(Book book);
}
 
public interface Book extends Entity {
    public String getName();
    public void setName(String name);
 
    @ManyToMany(Authorship.class)
    public Author[] getAuthors();
}

The code is very similar to the @OneToMany example, with the exception that here we have to provide the class for the intermediary “mapping table”. Once again, the dynamic proxy will find the @ManyToMany annotation, and using the table name for the intermediary table, derive a query relating books to authors based on any relevant mapping fields within Authorship.

Note: while the example given does use the @ManyToMany annotation on both “ends” of the relation, this isn’t required. The annotation merely informs the proxy handler on how to deal with the method call (as well as ensures the schema generator ignores the method signature).

An Easier Java ORM Part 4

30
Jul
2007

In keeping with my ActiveObjects series, here’s part 4. In this part, we’ll look at schema generation/migration and the ever-interesting topic of pluggable name converters and English pluralization.

One of ActiveObjects’s main concepts is that you (the developer) should never have to worry about the semantics of database design. You should simply be given the tools to design your models in a natural and object-oriented way, and the database just sort-of takes care of itself. To allow this sort of simplicity, the database schema has to be automatically generated, leaving nothing to the developer in this area. Fortunately, ActiveObjects does poses this capacity.

Schema Generation

In a nutshell, schema generation in ActiveObjects works by parsing the specified entity interfaces. First, a dependency tree is built, ensuring that the schema generation occurs in the proper order satisfying all dependent tables. ActiveObjects does generate all foreign keys for you, ensuring data integrity and maximum performance. This of course has the unfortunate side effect that everything must be inserted in the proper order; hence the tree.

Next, the dependency tree is passed through a loop which iterates through it and invokes DatabaseProvider#render(DDLTable), which generates the database-specific DDL statements necessary to create the entity-corresponding schema.

This all sounds fine-and-dandy on paper (or in this case, screen), but when you actually try to implement it in a real-world senario it gets a bit sticky. For one thing, Java’s types are nowhere near as robust as the ANSI SQL types. Additionally, almost every DDL allows developers to put certain restrictions on fields such as default values, auto incrementing or even forcing table-unique values. The solution, avoiding XML and other non-Java meta-programming, is to use annotations:

public interface Person extends SaveableEntity {
    public String getFirstName();
    public void setFirstName(String firstName);
 
    @Unique
    @SQLType(precision=128)
    public String getLastName();
 
    @Unique
    @SQLType(precision=128)
    public void setLastName(String lastName);
 
    @SQLType(Types.DATE)
    public Calendar getBirthday();
    @SQLType(Types.DATE)
    public void setBirthday(Calendar birthday);
 
    @Accessor("url")
    public URL getURL();
    @Mutator("url")
    public void setURL(URL url);
}
 
// ...
manager.migrate(Person.class);    // generates and executes the appropriate DDL

It might seem a bit ugly and annotation-ridden, but it does the job well and in pure-Java. There are more annotations which could be used (@OnUpdate, @Default, etc…), but these suffice to give a basic example.

You’ll notice right off the bat that each annotation has to be applied to both the accessors and the mutators. This is for two reasons. First, Java reflection doesn’t guarantee any particular ordering in which it will return the methods for a Class<?>. Thus, either the accessor or the mutator could be reached first and used to generate that field’s DDL, meaning the metadata needs to be applied to both or it could possibly be ignored by the schema generator. Second, ActiveObjects allows for read-only or write-only fields, meaning you don’t need the full accessor/mutator pair to access the database, one will suffice. This could be useful for application static data or for fields you just-plain don’t want the application to be able to mutate directly. Because ActiveObjects doesn’t assume an accessor/mutator pair, it can’t just wait for both the accessor and the mutator to be parsed. Thus, meta is required on both.

The other point of interest in this example is the use of the @Accessor and @Mutator annotations. From very early on, ActiveObjects has allowed developers to specify non-conventional method-names as database fields. In this case, ActiveObjects would normally assume the getURL method corresponded to to the “uRL” field (case intentional). This is because AO will assume the default Java get/set/is convention and recase the method accordingly. Since we obviously don’t want that for the “url” field, we use the @Accessor and @Mutator annotations to override ActiveObjects’s field name parser.

Pluggable Name Converters

By default, ActiveObjects uses a very simple set of heuristics to determine the table name from the entity class name. Essentially, this heuristics boil down to a simple camelCase implementation. For example, the “Person” entity would correspond to the “person” table. A “BillingAddress” entity would be mapped to “billingAddress” and so on. This is nicely conventional, but certainly not everyone would agree with this style of table naming. This is why ActiveObjects provides a mechanism to override the table name conversion and specify a custom algorithm.

The name converter interface is pretty simple. It has a single method (getName(Class<? extends Entity>):String) which is where the actual “meat” of the conversion happens. It also defines four algorithmically optional methods, which are intended to be used by developers as a quick-and-easy way to specify explicit mappings (for example, sometimes you want to override the algorithm for a specific class or name pattern without adding the @Table annotation to the entity). These methods are important, but could be left as stubs for a custom name-converter used “in house”.

To make it easier to write custom name converters, an abstract superclass has been created which handles most of the “boiler plate” functionality. I would recommend that this superclass (AbstractNameConverter) be used in lieu of a direct implementation of PluggableNameConverter. The only difference is that instead of overriding the getName(Class<? extends Entity>):String method from the superinterface, the method to override is getNameImpl(Class<? extends Entity>):String. This is the method called by AbstractNameConverter if the entity class in question fails to match an existing mapping.

Specifying the name converter to use is as simple as a single method call to EntityManager:

manager.setNameConverter(new MyNameConverter());

From that moment onward, all operations handled by that EntityManager instance (including schema generation) will use the specified pluggable name converter. This allows us to do some interesting things which would be otherwise out of reach…

English Pluralization

Table name mappings like {Person => person} and {BusinessAddress => businessAddress} may be conventional and nicely deterministic, but most people like database designs which reflect the underlying data a bit better. Since tables by definition contain multiple rows, it only makes sense that their names should be pluralized. Since we now have a mechanism to override the default name converter, we should be able to create an implementation which handles this pluralization for us for an arbitrary English word.

To accomplish this, ActiveObjects defines a class PluralizedNameConverter in the “net.java.ao.schema” package which extends the default CamelCaseNameConverter. The actual implementation within the name converter is fairly simple. All the algorithm needs to do is load an ordered .properties file (included with ActiveObjects) which contains all of the pluralization mappings as regular expressions. (e.g. “(.+)={1}s”) These mappings are then added to the name mappings implemented in AbstractNameConverter, which handles the semantic details of mapping the generated (in CamelCaseNameConverter) singular CamelCase names to their pluralized equivalents. Thus, PluralizedNameConverter doesn’t really do much work at all, the real action is in the abstract superclass as it handles the actual logic defined in englishPluralRules.properties. This is where the real interest lies. However, detailing all of the ins and outs of English pluralization rules would extend this article even farther beyond the breaking point; so I will have to revisit the topic in a future post.

To use the English pluralization for your own projects, simply initialize your EntityManager instance in the following way:

EntityManager em = new EntityManager(jdbcURI, username, password);
em.setNameConverter(new PluralizedNameConverter());
// ...

Now, the Person class will map to the “people” table. Likewise, the BusinessAddress entity will correspond to the “businessAddresses” table. Just like magic! :-)

It’s not a silver bullet, and I’m sure you’ll come across situations where the pluralization will be invalid. This is one of the reasons why manually adding mappings to name converters is possible. My only request is that you send your mappings my way so that I can include them in the properties file, allowing others to benefit from your wisdom.

However, despite all the rules (both manual and default) which can be specified, automatic English pluralization is still a very inaccurate science. Thus, the decision was made not to make pluralization the default name conversion method for ActiveObjects, in contrast to the same decision with ActiveRecord, which is pluralized by default. Hopefully, by not forcing pluralization upon you, I’ve made database design with ActiveObjects a little less stressful than it otherwise could have been. :-)

Conclusion

In conclusion: I write blog posts that are way too long. I hope this taste of automated schema generation and name conversion algorithms was helpful and useful to you in your quest for that ever-elusive, intuitive ORM.

(P.S.)

One of the things I’m currently working on for the upcoming ActiveObjects 0.4 release is the concept of schema migrations. Migrations are a little different than a straight schema generation as they don’t eliminate pre-existing data, but merely convert the existing tables to match the current schema definition. This is a mind-bogglingly useful feature in database refactoring, a common activity early in the application design process. Unfortunately, it’s also rather hard to do correctly. If you’d like to check up on my progress, criticize my coding style, or just play with the latest-and-greatest version, feel free to checkout ActiveObjects from the SVN: svn co https://activeobjects.dev.java.net/svn/activeobjects/trunk/ActiveObjects

An Easier Java ORM Part 3

24
Jul
2007

As a continuation to part 1 and part 2, this article examines a slightly less interesting (though none-the-less important) feature, transactions in ActiveObjects.

I also figured I should give a minor update on the development status. Eelco Hillenius (of the Wicket project) has been contributing some code, fixing up areas where I messed up and cleaning up one of the sample projects (the DogfoodBlog sample, based on Wicket). We’ve also been looking into areas where Wicket and ActiveObjects could be more easily integrated (such as entity-specific models and lists). I’ve been keeping busy trying to stabilize some of other database providers. We now officially support (in the trunk/) the following databases:

  • Derby (standalone and embedded)
  • MySQL
  • PostgreSQL
  • Oracle (with the limitation that @AutoIncrement is only supported on primary keys)

We also have the following (almost untested) providers:

  • Microsoft SQL Server (Microsoft and JTDS providers)
  • HSQLDB (standalone and embedded)

I’m hardly an expert in any of the above databases, so I welcome any and all input on bugs/errors/etc…

Transactions

While I might qualify transactions as comparatively unimportant, anyone who’s written a multi-user web application knows how significant they can be in maintaining data integrity. An ORM which didn’t support transactions would be sorely crippled indeed.

Hibernate solves the problem of transactions by forcing every database action to be wrapped in a transaction and committed at the close. This works well, but the significant downside is that it increases code complexity and forces the developer to remember to explicitly close every transaction. As before, I’ve tried to take some inspiration from ActiveRecord’s implementation of concepts:

p = Person.find(1)
lc = LibraryCard.find(321)
 
transaction do
    p.first_name = 'Daniel'
    p.last_name = 'Spiewak'
    p.save
 
    lc.person_name = 'Daniel Spiewak'
    lc.save
end

As is typical of ActiveRecord, this is an amazingly intuitive syntax. Unfortunately, again in accordance with the ActiveRecord MO, it depends upon a very DSL-like syntax. We might not be able to match the syntax exactly in Java, but we can fairly close:

new Transaction(manager) {
    public void run() {
        Account david = getEntityManager().get(Account.class, 1);
        david.setValue(david.getValue() - 1000);
        david.save();
 
        Account mary = getEntityManager().get(Account.class, 2);
        mary.setValue(mary.getValue() + 1000);
        mary.save();
    }
}.execute();

Obviously, we could potentially have gone with the less verbose:

Transaction t = new Transaction(entityManager);
t.begin();
// blah
t.commit();

However, this syntax doesn’t have the major advantage of the ActiveRecord DSL which is ensuring the transaction is closed. Also, with our anonymous inner-class syntax, we can do something like this:

new Transaction(manager) {
    public void run() {
        // yadda yadda yadda
    }
}.executeConcurrently();

This will execute the transaction in a separate thread, rather than blocking the current one. I haven’t actually seen a proper use-case for this so far, but it’s bound to have some application. :-)

Limitations

The trick with transactions in JDBC is all queries must be run against the same Connection instance. To accommodate this, an internal abstraction class is used by the ActiveObjects interface proxy to ensure that if a transaction is in progress, a single Connection is used, rather than opening a new one from the database provider. This works quite well, but it has its limitations.

Specifically, any custom code executed within the transaction which uses a Connection instance directly will run its SQL statements outside of the transaction boundaries. Any EntityManager method (get, find, findWithSQL, count, etc…) will work within a transaction, but any direct use of a Connection instance will likely cause unexpected behavior. I have a plan to fix this problem, but I haven’t gotten around to implementing it yet. Hopefully in a shortly upcoming release…

An Easier Java ORM Part 2

19
Jul
2007

Well, by popular demand on the first post, I now bring you the second part in my series introducing the new Java ORM, ActiveObjects. In the first post, I gave some very basic examples of how AO could be used to simplify database access in your application. And while trivially interesting, these examples really don’t do justice to the power of AO’s interface model and how it can best be used to serve you. So, I will be devoting this post to SaveableEntity(s) and implementations.

SaveableEntity

SaveableEntity is an interface which extends the Entity super-interface designed to overcome the inherent performance drawbacks in a simple getter/setter model ORM. For example, suppose we have the following trivial Entity interface:

public interface Person extends Entity {
    public String getFirstName();
    public void setFirstName(String firstName);
 
    public String getLastName();
    public void setLastName(String lastName);
}

We could use this entity in the following way:

private void initializePerson(EntityManager em, String name) throws SQLException {
    String[] names = name.split(' ');
 
    Person p = em.create(Person.class);
    p.setFirstName(names[0]);
    p.setLastName(names[1]);
}

This is all well and good, until we look at the actual SQL being executed by this code:

INSERT INTO person (id) VALUES (DEFAULT);
UPDATE person SET firstName = ? WHERE id = ?;
UPDATE person SET lastName = ? WHERE id = ?;

These are executed as separate PreparedStatement(s), under separate connections, totally unconnected. If we didn’t include a pooling library in the classpath, the connections wouldn’t be pooled and we would incur a significant performance hit from this sort of thing.

Enter SaveableEntity. SaveableEntity prevents the setters from immediately executing their respective UPDATE statements. Rather, the UPDATEs are held in reserve until the save() method is invoked. Here’s the above example rewritten to use SaveableEntity:

public interface Person extends SaveableEntity {
    public String getFirstName();
    public void setFirstName(String firstName);
 
    public String getLastName();
    public void setLastName(String lastName);
}
 
private void initializePerson(EntityManager em, String name) throws SQLException {
    String[] names = name.split(' ');
 
    Person p = em.create(Person.class);
    p.setFirstName(names[0]);
    p.setLastName(names[1]);
    p.save();
}

Only one more line of Java code, but it diminishes the SQL executed by 30%:

INSERT INTO person (ID) VALUES (DEFAULT);
UPDATE person SET firstName = ?,lastName = ? WHERE ID = ?;

This might not seem like such a big deal when you’re only working with single and duel fielded entities, but when you get into far more complex models – say, on the order of 30-40 fields – it makes a big difference if UPDATEs are merged where possible.

Implementations

So on a swift turn round another tack, we’re now going to look at defined implementations in ActiveObjects and how they are both a) a major pain you-know-where, and b) incredibly useful.

As was pointed out in a comment on my last post, ActiveObjects as I have presented it so far is just a data wrapping layer. It just allows simple database access. No frills, and no model-specific business logic. This actually poses a bit of a problem in many senarios.

For example, let’s assume you have a basic, user-based authentication system. Each user has a username and a password. However, authentication best practice says not to store the password in clear-text in the database. In fact, it’s best to hash the password when it is stored to prevent anyone from decrypting it. The problem comes in that ActiveObjects doesn’t allow us to do something like that in its current form. You’d have to do all the hashing prior to calling User#setPassword(String), and that would be majorly painful and about as unDRY as it gets. The solution: defined implementations.

@Implementation(UserImpl.class)
public interface User extends SaveableEntity {
    public String getUsername();
    public void setUsername(String username);
 
    public String getPassword();
    public void setPassword(String password);
}
 
public class UserImpl {
    private User user;
 
    public UserImpl(User user) {
        this.user = user;
    }
 
    public void setPassword(String password) {
        user.setPassword(Utilities.md5sum(password));
    }
}
 
// ...
User u = em.create(User.class);
u.setUsername("daniel");
u.setPassword("password");
u.save();
 
System.out.println(u.getPassword());   // prints the MD5 hashed value of "password"

See what I mean about a major pain? It’s not exactly clear what’s going on here so I’ll give you a brief run-down:

  • EntityManager instantiates a dynamic interface proxy for the User interface and returns it (where it assigned to u). It sees the @Implementation annotation and looks in the class for an init() method. Not finding one, it moves on.
  • setUsername(String) is invoked on the dynamic proxy. An @Implementation annotation on the interface is detected and the class in question is instantiated, passing the User instance into the constructor. The proxy looks for a setUsername(String) method within the implementation class and doesn’t find one. The method is invoked normally, caching the String username for future UPDATE into the database.
  • setPassword(String) is invoked. The dynamic proxy once again finds the @Implementation annotation and thus uses the cached UserImpl instance, looking for a setPassword(String) method. This time, it finds one and invokes it.
  • UserImpl#setPassword(String) is invoked by the dynamic proxy. The method calls to a utility class to hash the password, and in turn calls User#setPassword(String) with the resulting value.
  • The dynamic proxy receives the setPassword(String) call, and uses stack tracing to detect that the call originated from a defined implementation. The call is handled normally, caching the result for future UPDATE into the database.

Not so bad, I guess… The trick to remember is that any defined implementation takes an instance of the interface as the only parameter to its constructor. Also, it’s important to remember to only implement the methods that you expressly want to override. By defining a method in the implementation class, you are effectively overriding the dynamic implementation of any method with the same signature in the entity interface. This can lead to weird results if you aren’t careful.

So, we’ve now got SaveableEntity and defined implementations under out collective belts. With these two features, you can unlock a great deal of power and control over the ActiveObjects ORM and the entities it controls.