Thursday, December 21, 2006

Through the looking glass

(Congratulations to me, the 1,000,000th person to use this title in this context)

Project Looking Glass, Sun's Java 3D desktop (Vista Killer) has finally released 1.0.0, and of course I had to check it out. Here's a screenshot:

Wednesday, December 20, 2006

Transactions and exceptions revisited

As Jonas (Hello, world!) embarrasingly enough pointed out, the default Spring transaction semantics with respect to exceptions are identical with EJB's (you can't escape EJB!). So that's why Spring doesn't roll back on checked exceptions, but the question remains: why would anyone ever not want to roll back a transaction when an exception is thrown, checked or unchecked?

We had a long discussion which I'm going to try and sum up here. Obviously you (almost) never want an exception to leave the transactional layer without rolling back the transaction, since that means that something went wrong, but the transaction commited anyway. Suppose you have something like this:

@Transactional
public void registerNewUser(User user) throws LDAPException {
log.info("Registering user: " + user);
userDao.insertUser(user);
ldapService.registerEntry(user.getFirstName(), user.getLastName()); // Let's assume this throws a (checked) LDAPException
}

in the service layer, and then you call this method from outside the service layer, for example in an MVC controller. Now if the call to create the LDAP entry fails (throws a checked exception), the user data is stored even though an exception is thrown out to the calling controller, which can't do anything about it.

This scenario could be handled in two different ways, depending on business requirements: either a failed LDAP registration is fatal, and we need to roll back the transaction to avoid storing user data, or an LDAP exception is not fatal and we should catch and gracefully handle the failure inside the registerNewUser() service method.

If we decide to roll back, we have a few options:
So far it seems that simplifying the rollback rules to "always roll back on an Exception, I don't care if it's checked" is a good idea. But if it's the case that an LDAPException isn't fatal after all, the situation becomes a little more complicated. We modify the method like this:

@Transactional
public void registerNewUser(User user) {
log.info("Registering user: " + user);
userDao.insertUser(user);
try {
ldapService.registerEntry(user.getFirstName(), user.getLastName()); // Let's assume this throws a (checked) LDAPException
} catch (LDAPException e) {
// Log and move on
log.error("LDAP registration failed: " + e.getMessage());
}
}

No checked exception is thrown anymore. Furthermore, assume that the LDAP service call is also transactional, and that we're using the default propagation behaviour, REQUIRED, so that the LDAP service call participates in the same transaction as the registerNewUser() started. If the rule is to always roll back on any transaction, the exception thrown in the LDAP service call will mark the current transaction for rollback, even though we catch it in the user service method! That means that we have lost the ability to pass on failure messages between horizontal transactional calls (service-to-service).

So to conclude:
  1. We need to keep a way to pass on failure messages between calls inside the same transaction, and checked exceptions are a good candidate for that (certainly better than returning a negative integer).
  2. You should not expose service methods that throw checked exceptions to layers above/outside the transactional layer.

Thursday, December 14, 2006

This you need to know

Section 9.5.3 in Spring's reference documentation explains how and when transactions are rolled back, and also states the default behaviour with respect to rolling back transactions. The behaviour might not be what you expect (quoted):

However, please note that the Spring Framework's transaction infrastructure code will, by default, only mark a transaction for rollback in the case of runtime, unchecked exceptions; that is, when the thrown exception an instance or subclass of RuntimeException. (Errors will also - by default - result in a rollback.) Checked exceptions that are thrown from a transactional method will not result in the transaction being rolled back.

Note the very last sentence (my bold). Checked exceptions do not trigger a transaction rollback!

There is of course a way change this behaviour by listing an array of Exception classes for which to roll back for, the details are in section 9.5.3 and below.

Personally I find this quite counter-intuitive, but I suppose there is good reason for this default behaviour. In either case, it's very important to be aware of how it works.

Wednesday, December 13, 2006

Faster DAO testing

If you're prepared to step away just a little bit from how the production environment is set up, here's one way to speed up Hibernate DAO testing considerably:

First of all, don't add a (Annotation)LocalSessionFactoryBean to your test context, just a DataSource and a hibernate.cfg.xml, and don't add any mapped/annotated classes to the configuration file either. Then create a base DAO test class that looks something like this:

public class AbstractDaoTest {

SessionFactory sessionFactory;

public AbstractDaoTest(Class... classes)
{
// Read hibernate.cfg.xml from root of classpath, for example src/test/resources
Configuration configuration = new Configuration();
for (Class clazz : classes) {
configuration.addClass(clazz);
}
sessionFactory = configuration.buildSessionFactory();
}

}

Then place all your DAOs and the DataSource in the test application context, and start writing your DAO tests like this:

public class ParentDaoTest extends AbstractDaoTest {

ParentDao dao;

public ParentDaoTest() {
// Parent has a relation to the Child class, so we need two classes mapped
super(Parent.class, Child.class);
}

public void setParentDao(ParentDao dao)
this.dao = dao;
}

public void testSomething() {
// Stuff that involves Parent and Child
}

}

Now there's only two classes that Hibernate needs to parse metadata for and create CRUD SQL for and so on, which can speed up application context startup considerably compared to mapping all domain classes, if you have 10-20 classes in you domain model.

Sunday, December 10, 2006

YES

He's on his way!

Go Christer!

Thursday, December 07, 2006

En vän har gått ur tiden

Min katt Morrissey dog idag. Han hade en medfödd, obotlig njursjukdom som till slut blev för svår att uthärda, och han somnade in på sin lurviga fäll hemma i soffan efter en överdos sömnmedel.


Tack Yvonne på Djurdoktorn för all hjälp.



Lillmosse, 2002-07-04 - 2006-12-07

Friday, November 24, 2006

The dark side

Christmas came early this year:









Monday, November 20, 2006

One less headache thanks to Tiger

You are familiar with the old Arrays.asList(Object[]) call for converting an array to a List. You're also sick of doing this:

List list = new ArrayList();
list.add(Integer.valueOf(1));
list.add(Integer.valueOf(2));
list.add(Integer.valueOf(3));

Well, thanks to autoboxing and varargs, you can do this instead:

List list = Arrays.asList(1, 2, 3);

Sure, it's not a huge deal, but it's just better in every sense of the word.

Saturday, November 11, 2006

Testing Hibernate DAOs with Spring

Spring has an enormous amount of utility/help/glue code, that can simplify a lot of common tasks, but it's not easy to get a good overview of everything that's available. One of the core areas of Spring is of course testing, and I'm going to show one way to write unit tests (or integration tests, if you insist) for Data Access Objects implemented using Hibernate, against a real database.

To begin with, most of the work has already been done by Spring. In the
org.springframework.test package there are a number of helper classes on top of JUnit for in-container testing. We are going to make use of an application context, a data source and transactions, so we're going to with AbstractTransactionalDataSourceSpringContextTests, which is coincidentally the longest class name in Spring. This class has a number of cool features:

  • It keeps a static cache of application contexts based on the string array of file names defining the context, so you only need to initialize the context once per test class*.
  • It autowires the test itself, by type. (It's also possible to change to autowire-by-name, or turn it off)*
  • It runs every test inside a transaction, which is rolled back after each test (unless you say otherwise).
  • It makes a JdbcTemplate available for low-level database operations.
  • Instead of the setUp()/tearDown() callbacks, it has callbacks before transactions start, inside the transaction but before the test, after the test but inside the transaction and finally after the transaction has been rolled back.
(* Thanks Robert for the pointers.)

I usually organize my applicationContext files so that every environment-dependant bean - such as the data source, SMTP server or whatever - is in a separate file called applicationContext-env.xml. Also, each of the dao-, service- and mvc layer have their own context file. Using that setup we would use the applicationContext-dao.xml file, and a test-specific applicationContext-env.xml. If you keep your context files in the classpath and use Maven and the standard directory layout, overriding context files work out of the box. Specifically, you can keep one version of applicationContext-env.xml in src/main/resources pointing at a JNDI exposed data source that's picked up from the application server, and another in src/test/resources looking somthing like this:

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="url" value="jdbc:postgresql:myapp_test"/>
<property name="driverClassName" value="org.postgresql.Driver"/>
<property name="username" value="my_db_user"/>
<property name="password" value="******"/>
</bean>

In addition to this, you can have a test-specific hibernate.properties in src/test/resources that turns on SQL debugging and other things:

hibernate.show_sql=true
hibernate.format_sql=true

Don't deviate too much from the production environment though, by doing things like turning off the second-level cache or whatever, since that decreases the value of the tests. We want our testing to be as close to reality as possible, that's why where using the same database (application) as in production, instead of something like Hypersonic.

Now we're ready to implement our first method, which we'll do in a base class for all our daos. You ususally have a number of daos that use the same combination of context files, the same batch file with test data and which all need a reference to the SessionFactory. So, here's our AbstractDaoIntegrationTest class:

public abstract class AbstractDaoIntegrationTest extends AbstractTransactionalDataSourceSpringContextTests {

SessionFactory sessionFactory;
SimpleJdbcTemplate jt;

public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}

@Override
protected String[] getConfigLocations() {
return new String[] {
"applicationContext-dao.xml",
"applicationContext-env.xml"
};
}

@Override
protected void onSetUpBeforeTransaction() throws Exception {
jt = new SimpleJdbcTemplate(jdbcTemplate);
}

@Override
protected void onSetUpInTransaction() throws Exception {
super.onSetUpInTransaction();
// Load a batch of test data in the transaction
executeSqlScript("classpath:test-data.sql", false);
}

// Utility method
protected void flush() {
sessionFactory.getCurrentSession().flush();
}

}


The SessionFactory bean obviously needs to be available in one of the context files, I usually keep ORM configuration along with dao declarations. As you can see, an SQL file of test data is loaded at the beginning of the transaction. This data is rolled back at the end, eliminating the need for any manual cleanup. This works well for any reasonable amount of test data, but maybe not if you need a million records loaded. The actual test will be hard-coded against the test data file, when verifying load and finder methods. We're also wrapping the JdbcTemplate with the new and simpler (!) SimpleJdbcTemplate, which makes use of varags for parameter matching for example.

Now we can start writing dao tests on top of the above class. I'm going to use an EmployeeDao for this blog entry.

public class EmployeeDaoTest extends AbstractDaoIntegrationTest {

EmployeeDao employeeDao;

public void setEmployeeDao(EmployeeDao employeeDao) {
this.employeeDao = employeeDao;
}

}

This is all we need to get started with the actual tests! Very clean and simple. Let's look at load, store and delete testing in turn.

public void testLoadEmployee() throws Exception {
Employee employee = employeeDao.load(7L);

assertEquals("197708170000", employee.getUsername());
assertEquals("test-password", employee.getPassword());
assertEquals("test.realm", employee.getRealm());
assertEquals("197708170000@test.realm", employee.getJid());
assertEquals("test-firstName test-familyName", employee.getName());
// Assert every property
}

The important principle in action here is that you test one ORM operation against a known database state, namely the test batch file.

Note that unless we close the Hibernate session manually, the session remains open during the test, so that lazy relational restrictions will not be effective here. We'll test that later though.

Store testing is similar, we build an Employee in Java code, store it using the ORM, and the compare against the actual database state.

public void testStore() throws Exception {
Employee employee = new Employee();
employee.setUsername("197708306621");
employee.setPassword("_password");
employee.setRealm("_realm");
employee.getRoles().add(User.Role.CUSTOMER);
employee.getRoles().add(User.Role.EMPLOYEE);
employee.getRoles().add(User.Role.TRANSLATOR);
employee.getVcard().setFirstName("_firstName");
employee.getVcard().setFamilyName("_familyName");

// Store
employeeDao.store(employee);
// Flush manually, to make sure the SQL is issued
flush();

// Start assertions by loading data from the database using the JdbcTemplate
assertNotNull(employee.getId());
Map authregMap = jt.queryForMap(
"select * from authreg where id = ? " +
"and class = 'se.petrix.iaba.model.user.Employee'", employee.getId());

assertEquals("197708306621", authregMap.get("username"));
assertEquals("_password", authregMap.get("password"));
assertEquals("_realm", authregMap.get("realm"));

// Roles
List<Map<String,Role>> roles = jt.queryForList(
"select role from authreg_roles where authreg ? order by role",
employee.getId());

assertEquals(3, roles.size());
assertEquals(Role.CUSTOMER.name(), roles.get(0).get("role"));
assertEquals(Role.EMPLOYEE.name(), roles.get(1).get("role"));
assertEquals(Role.TRANSLATOR.name(), roles.get(2).get("role"));
}


Here you can see the SimpleJdbcTemplate in action. It's really simple to read data for verifying against what we fed the Employee instance with.

Next comes deletion, which is fairly simple in comparison.

public void testDelete() throws Exception {
employeeDao.delete(7L);
flush();

// Employee
assertEquals(0, jt.queryForInt("select count(*) from authreg where id = 7"));
// Roles
assertEquals(0, jt.queryForInt("select count(*) from authreg_roles where authreg_id = 7"));
}

Here's where you would test your cascade-delete mapping settings, by making sure that data in related tables is or isn't deleted, according to your configuration.

Finally we'll take a look at how you can test lazy relations. It could be argued that this belongs in the service layer tests, but the same method can easily be applied to the service layer, just include applicationContext-service.xml and write tests against that layer.

Suppose that Employee has a Set<Customer> of customers that he or she is responsible for, and that the relation is lazy. An Employee also has a Set<Role> of roles, that isn't lazy.

public void testEmployeeRelations() throws Exception {
Employee employee = employeeDao.load(7L);
// Manually end the transaction, which closes the Hibernate session
endTransaction();

try {
Role role = employee.getRoles().iterator.next();
// Success
} catch (LazyInitializationException e) {
fail("Employee.roles relation should not be lazy");
}

try {
Customer customer = employee.getCustomers().iterator.next();
fail("Employee.customers relation should be lazy");
} catch (LazyInitializationException e) {
// Success
}
}

That's it for today, good luck and as always, comments are welcome.

Monday, November 06, 2006

November spawned a Florence

Robert och Joanna blev föräldrar idag, till en liten flicka som ska döpas till Florence (eller kanske phl0renZ)? Jag hoppas få se henne senare i veckan, det ska bli spännande. Stort grattis och lyckönskningar från mig och Sofia!

För fratida referens noterar vi att den 6 november 2006 är Elfsborg nyblivna svenska mästare i fotboll, Fredrik Reinfeldt nybliven statsminister och Googles senaste påhitt en mobil Java-klient till Gmail.

Sunday, October 29, 2006

Continuum and SSL authentication solved

We got SSL authentication working in Continuum this Friday, by applying this one-line patch that we found in the JIRA. These are the steps that we followed, roughly:
  1. Checkout the source:

    svn co http://svn.apache.org/repos/asf/maven/continuum/tags/continuum-1.0.3/
  2. Apply the patch (it's just one line, so it's trivial to apply it by hand).
  3. Build the whole thing with Maven:

    mvn -Dmaven.test.skip=true -DappProperties=app.properties install
    Some tests failed, and I didn't have the time to investigate further, and one of the modules failed to find the app.properties file automatically. Also, you may need to download and install some Sun jars manually, but that's not a big problem since Maven hands you a command line to use.
Now Continuum is ready to run, if the build succeeds. There is a build guide, and a README that contains additional information. In our case, we have a hierarchy of projects which are automatically identified and set up in Continuum. Very handy!

Sunday, October 22, 2006

New job

I've just completed the first week on my new assignment: consulting team member on a medium sized project for Eniro. It's been a great experience so far, and although I can't reveal the exact nature of the project, I can say that it's based on high profile open source Java EE components such as Spring, Hibernate, MySQL, Linux, Velocity and Maven.

I've worked quite a bit with most of the stuff before, but one thing that's new to me is Maven multi-module project hierarchies which works quite well, and makes Maven look even better. Another nice thing that I've never used before is Maven Proxy.

One thing we decided on early on was to use contiuous integration, and since we're heavy users of Maven already, Continuum seemed like a sane choice for server. Unfortunately we've having problems getting it to work with SSL+authentication...

The project is based on an older application which has been split into three major parts, with each part having two or three sub-parts. The older application did have a partial test suite, but it hadn't really been kept up to date the latter half, so the first step will be to resurrect and/or rewrite the testsuite. This situation is fairly common in my experience, where you start out writing tests for everything, but as the project progresses, people pay less and less attention to testing, and the suite drifts further away from the code base. Hopefully CI will counter this behaviour :-)

My methodology for writing DAO testing against a database was accepted with some enthusiasm. I've written a little about it in "Rolling with Spring and Hibernate", but I'm planning a larger entry on that subject. An update on that article is planned, too. Stay tuned!

Friday, October 06, 2006

Patch accepted

I got my first patch accepted into Spring today, a small fix for the FreeMarker view class. It'll be present in 2.0.1. Very fast response from the core team (Jürgen), impressive!

I've also worked a little on the CSS of this blog. I really think serif fonts are more readable in the long run. Gotta do something about that awful header though. This was the only Blogger template I could find that spanned the full width of the page, so I figured I'd start from there and customize it later on.

Thursday, October 05, 2006

About the "Rolling with..." article

For those of you interested in reading the "Rolling with Spring and Hibernate" article series, here's a quick recap of the contents:
  1. The first part is just about APIs and development environment.
  2. The second part begins the building of the model, with Hibernate and transaction configuration and a basic CRUD-able entity class.
  3. In the third part a controller and a few views are added, and the application is deployed for the first time. Also a few notes about AspectJ weaving and Jetty.
  4. Part four adds a second class to the model, and a relation between the two model classes. Here we can see what amount of work is needed to add one more model class to an existing application.
  5. Testing is covered in part five, both mock testing and integration testing against a database.
  6. And in the final part I comment a little on the differences between Rails and the stack at hand, and some suggestions for Spring improvement.
Any comments and suggestions are welcome. The code is available as a Google Code project. Embarassingly enough, I've misspellt "Recipe" as "Recipie" thoughout the application, but the blog text is corrected. Refactoring recipie->recipe is left as en excercise to the reader :-)

Update: those of you who find this article interesting, might also enjoy this more recent in-depth look at implementing the ActiveRecord pattern using Spring and Hibernate.

Monday, September 25, 2006

Rolling with Spring and Hibernate, part 6: summary and reflections

This series of blog entries was meant to compare speed and ease of development of the Spring 2.0 and Hibernate/JPA combination with Ruby on Rails, and also to take a closer look at the new Rich Domain Model support in Spring 2.0. I am by no means an expert on RoR, I've mostly tinkered with a few toy projects to get a basic hang of it. My experience with Spring and Hibernate is a lot more extensive, going back to a few months before Spring 1.0 was released in March of 2004.

Obviously it's a lot more work to get started with this stack than RoR, but that can be vastly improved with a good prototype project. There are a number of options, ranging from a slightly expanded Maven standard archetype to Appfuse. Usually you can modify an existing project, maybe maintain a company-wide standard application - or even use spring-cookbook :-). In either case, it's not a big deal in a real world situation, since the time spent in this phase is a tiny, tiny part of the whole project. It does matter for newbies, though.

What's more important and interesting is the time and effort needed to make a change to the application. You often see the argument that RoR is more productive because you need to write less code to accomplish the same feat. Case in point: the infamous Hello World application...Ruby first:

puts "Hello, World!"

And the same thing in Java:

public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, world!");
}
}

Clearly a big advantage for Ruby, wouldn't you say? ;-)

Jokes aside, code-completion compensates for more verbose syntax IMHO. Actually writing code isn't really time-consuming, but the number of places where you have to edit code for a particular change in the application to happen, does matter. It matters a lot. Suppose you have a Car in your domain model, and you want to add a color property. In RoR, you add the column "color" to the table "cars" in the database. That's it. There's no updating the ORM mapping files, no adding of a member , getter and setter for color in the Car class, no updating of DTOs or form beans, no extra handling of parameters. Unless you're using view scaffolding you will need to modify the views, however. This is a great boost to productivity, read- and maintainability of the application.

When working with Hibernate/JPA annotations, you get fairly close to this behaviour . Hibernate can auto-update the schema on changes to the Java model, and you only need to set the @Entity annotation on the class level for properties to be persistent by default. And there's no need for maintaining separate DTOs, as when working with EJB 2.x. If you're using the Spring MVC framework, you can even use arbitrary classes as form beans, and the domain model is of course a great candidate for that. So we can honestly say that we have a fairly competitive setup at hand.

A nice thing in Rails is the automatic conversion from id parameter to a related persisted entity, for example the category of a recipie in this particular application. The HTML form for editing a Recipe has a drop-down list where the parameter value is the id of the Category. Using Spring MVC, we need to write a (short) PropertyEditor to load and join the Recipie and the Category.

When it comes to URL mapping and controllers, Spring 2.0 brings a fantastic new addition to the table: ControllerClassNameHandlerMapping. Together with the MultiactionController we can work similarly to Rails: Any request that matches /car/* is handled by a CarController, and specifically by the method that has the same name as the end part of the url - /car/edit is handled by the edit() method, and so on. It works for other controller types as well, so you can have a SimpleFormController named EditCarController that's mapped to /editCar.

The edit-save-reload-cycle in the web server is almost zero in RoR, since Ruby is a interpreted language. Traditionally, this cycle has been very slow in Enterprise Java development, and even if you work extensively with out-of-container testing, you will need to see and test the actual application from time to time. Until we have on-the-fly class reloading in the JVM, we're going to have to reload the application after making changes to Java code. We can ease the pain by using a smart directory structure (as in this application) and a fast, handy servlet container that scans for changes and triggers reloads automatically. Another thing that's new in Spring 2.0 is the support for beans defined in script languages such as BeanShell, Groovy or even Ruby. You could for example write the controllers in Groovy and keep the service layer and everything below in Java. The possibilites are endless, and the big advantage of Spring is that you can gradually migrate to a simpler and more modern architecture while preserving and interacting with legacy components.

Working with a Rich Domain Model and IoC using the new @Configurable technique, is quite nice. It does require a few tricks and redundant configuration though. Passing the -javaagent parameter to the JVM requires setting shell variables or editing the server startup script, which is acceptable but easy to forget.

It's also unfortunate that there's no domain-specific shorthand XML configuration for the AspectJ transaction aspect, like <aop:aspectj-configured/>.

In general, it would be nice if you didn't have to specify what classes should be persisted twice, first with the @Entity annotation and the again the in SessionFactory configuration. Same thing with classes that need to be weaved with the IoC-aspect: first with @Configurable, and again in classpath:META-INF/aop.xml. With no detailed technical insight in the matter, here's how I'd like to write my configuration, using the same recursive package syntax as AspectJ:

<hibernate3:sessionFactory mappedClasses="se.petrix.cookbook.model..*"/>

<aop:aspectj-configured configuredClasses="se.petrix.cookbook.model..*"/>

<aop:aspectj-transactions/>

Better get to work on that patch then :-)

There is a lot of room for configuration improvment everywhere, now that the domain-specific XML framework is in place. My guess is that we'll see a lot of new XSDs during the 2.x series.

Mock testing is a little bit more difficult, but still manageable. If you're wiring a DAO or service layer into the model, you won't have to deal with chained interface calls either, such as sessionFactory.getCurrentSession().getCriteria(clazz).

How to write the CRUD methods is another difficult question. At first thought, the load operation isn't tied to a particular instance of an entity, since we don't have one yet. Therefore it should be static:

public static Recipe load(Long id) { ... }

Recipe r = Recipe.load(1L);

But there are two problems with this implementation: first, you don't want to make the persistence collaborator (the SessionFactory in this application, maybe a DAO layer or a DataSource in others) a static member. So, we have to wrap the static call with an instantiation:

public static Recipe load(Long id) {
return new Recipe().doLoad(id);
}

And secondly, you don't want to implement this method in every persistent domain class, instead you move it to the BasicEntity class. But how do we instantiate the parameterized class in a static context? We want something like this (in BasicEntity):
   
public static T load(Long id) {
return T.class.newInstance().doLoad(id);
}

Of course, that's not possible (T.class is illegal). I haven't found any way around this.

The choice, as I see it, is between wrapping load and other static methods such as finders in every persistent class, or completely skip static methods and instead choose one of the following styles:

// 1:
Category c = new Category().load(1L);
// 2:
Category c = new Category(1L).load();
// 3:
Category c = new Category(); c.setId(1L); c.load();
// 4: (perform a load operation in the constructor)
Category c = new Category(1L);

If anyone has opinions on this matter, please post a comment. I'm not convinced about the superiority of any of these solutions, but I've chosen the simplest one, number 3, in this application.

Rolling with Spring and Hibernate, part 5: testing

Testing a Spring/Hibernate/AspectJ rich domain application is not completely trivial. Normally, when working with the traditional three-tier architecture (DAO, service, controller), you utilize Inversion of Control instead of instatiating collaborators to be able to switch to mock implementations in isolated tests. When you're working with a rich domain model like this, the whole point is to place more logic inside the domain objects. They must in turn be provided with the necessary services through, in this case, aspect-driven IoC since it's impossible to avoid writing code that instantiates domain objects.

This means that if we want to test code that does instantiate a domain object, we can't inject a mock domain object - we have to inject the mock services into the domain object instance(s) created by the code we're testing.

In this application, there are only two "layers": the (rich) domain model and the controllers. Testing the model is simple, it's just like any normal DAO layer: we set up a test database and use the class with the world's longest name to test CRUD: AbstractTransactionalDataSourceSpringContextTests. It provides a few very useful things: the ability to run each test in a transaction that is rolled back, eliminating the need for manually cleaning the test database, IoC for wiring the tests themselves, and a JdbcTemplate for verifying the database operations and mappings. It's often a good idea to create a base class that loads test data and some other stuff that is common to all CRUD tests. Here's what I'm using:

public abstract class CookbookModelTest extends AbstractTransactionalDataSourceSpringContextTests {

SessionFactory sessionFactory;

public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}

@Override
protected String[] getConfigLocations() {
return new String[] {
"applicationContext-hibernate.xml",
"applicationContext-test.xml"
};
}

@Override
protected void onSetUpInTransaction() throws Exception {
super.onSetUpInTransaction();
jdbcTemplate.execute(
"INSERT INTO category (id, name) " +
"VALUES (10, 'Category 1')");
jdbcTemplate.execute(
"INSERT INTO category (id, name) " +
"VALUES (20, 'Category 2')");
jdbcTemplate.execute(
"INSERT INTO recipe (id, title, instructions, date, category_id) " +
"VALUES (1, 'Recipe 1', 'Test this recipe', '2006-09-10', 10)");
jdbcTemplate.execute(
"INSERT INTO recipe (id, title, instructions, date, category_id) " +
"VALUES (2, 'Recipe 2', 'Test this recipe too', '2006-09-11', 10)");
jdbcTemplate.execute(
"INSERT INTO recipe (id, title, instructions, date, category_id) " +
"VALUES (3, 'Recipe 3', 'Test this recipe three', '2006-09-12', 20)");
}

}

The session factory is useful for forcing a flush of the SQL commands to the database, for example when doing a delete, like we're doing here in the RecipeTest (inherits the CookbookModelTest above):

public void testDelete() throws Exception {
Recipe recipe = new Recipe();
recipe.setId(1L);
recipe.delete();
sessionFactory.getCurrentSession().flush();
assertEquals(0, jdbcTemplate.queryForInt("SELECT count(*) FROM Recipe WHERE id = 1"));
}

This illustrates the idea of using the JdbcTemplate to by-pass the ORM to verifty that the operation really resulted in the database changes we wanted.

Ok, that's the easy part. Now we move on to test the controller, which in some cases instantiates domain objects beyond our control. The fact that we're using the Hibernate API directly, and also the Criteria API, will make it a bit harder to set up mock expectations than if we had a plain DAO layer. Remeber how we build the Criteria queries:

@Transient
protected Session getSession() {
return sessionFactory.getCurrentSession();
}

@Transient
protected Criteria getCriteria() {
return getSession().createCriteria(this.getClass());
}

We have to mock both the SessionFactory, the Session and the Criteria...and make the mocks return other mocks! For example, we need to make the SessionFactory mock expect a call to getCurrentSession(), and return the Session mock (that in turn will expect other calls):

protected void expectGetCurrentSessionCall() {
sessionFactory.expects(once()).method("getCurrentSession")
.withNoArguments().will(new CustomStub("Session") {
public Object invoke(Invocation invocation) throws Throwable {
return (Session) session.proxy();
}
});
}

There's a similar method to set up an expectation to Session.getCriteria(clazz) in CookbookControllerTest.

In addition to this, we need an application context for weaving the domain objects according to the @Configurable annotation:

applicationContext = new StaticApplicationContext();
// It's a bit tricky to register a factory bean with a custom method name...
BeanDefinition aspectConfigurerDefinition = BeanDefinitionBuilder.
rootBeanDefinition(AnnotationBeanConfigurerAspect.class).
setFactoryMethod("aspectOf").getBeanDefinition();
// Register the configuring aspect
applicationContext.registerBeanDefinition(
AnnotationBeanConfigurerAspect.class.getName(), aspectConfigurerDefinition);
// Register the mocked session factory
applicationContext.getBeanFactory().
registerSingleton("sessionFactory",sessionFactory.proxy());
// Don't forget to refresh!
applicationContext.refresh();

This is a small application context that registers configuration aspect and the mock session factory, so that AspectJ can weave domain model classes according to classpath:META-INF/aop.xml, and inject the mock session factory on instatiation. With this in place in a controller test superclass, we can test a method that instantiates a domain object, such as this:

public ModelAndView create(HttpServletRequest request, HttpServletResponse response) {
List categories = new Category().findAll();
return new ModelAndView("recipe/edit", "categories", categories);
}

with the following code:

public void testCreate() throws Exception {
// This is a utility method to prepare mock request/response
prepareRequest("/recipie/create.htm", "GET");
expectGetCriteriaCall(Category.class);
List toReturn = new ArrayList();
toReturn.add(new Category());
toReturn.add(new Category());
criteria.expects(once()).
method("list").
withNoArguments().
will(returnValue(toReturn));

ModelAndView mav = controller.handleRequest(request, response);

assertEquals("recipie/edit", mav.getViewName());
List result = (List) mav.getModel().get("categories");
assertEquals(2, result.size());
}

Traditionally, we would mock CategoryService, and expect a call to listAllCategories(). No application context would be needed.

For those of you that feel that calls such as

new Category().findAll()

is hideous, I can only say that I agree, and we'll get to that in the final part.

Friday, September 15, 2006

Rolling with Spring and Hibernate, part 4: adding a relationship

We now have a basic application in place, that we can use to list, create, edit and delete recipes. The next step is to add the Category to our domain model, and create the relationship between Recipe and Category: a category contains many recipes, and a recipe belongs to one category.

The first step will be to create the Java class, which will inherit from BasicEntity. That way, we already have the id property and CRUD operations in place, and we only need to add one property (name) and the relation to Recipie. But we're going to start with just the name property. Here's the entire Category class:

@Entity
@Configurable(autowire=Autowire.BY_NAME)
public class Category extends BasicEntity<Category> {

String name;

public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}

}

That's the model, now we need the view and the controller. Controller first:

public class CategoryController extends MultiActionController {

public ModelAndView list(HttpServletRequest request, HttpServletResponse response) throws Exception {
List<Category> categories = new Category().findAll();
return new ModelAndView("category/list", "categories", categories);
}
...
// + create, edit and delete
}

The views are very similar to the Recipie, we won't go into detail right now.

That's all you need to do in order to add a new model object and controller the project! On deploy, Hibernate will update the schema to include the new @Entity, and the controller mapping is implicitly derived from the class name CategoryController. Check out http://localhost:8080/cookbook/category/list.htm.

At this point we're almost at par with Rails productivity. We don't have scaffolding, but the code generated by "scripts/generate Category scaffold" is more or less the same as what we've just written, and we edit the Java model class and get the table generated, instead of the other way around. Generated code still needs to be tested, understood and maintained, and code completion makes writing actual code easier in a statically typed language. And in a final product, you will still need to re-write all the scaffolded views, so sooner or later Rails will lose that particular advantage.

The next step is to implement the relation between Recipe and Category, and that's an area where Rails will come out on top. First, the model: Recipe belongs to one Category:
@ManyToOne
@JoinColumn
public Category getCategory() {
return category;
}

And Category has many recipes:

@OneToMany(mappedBy="category")
public Set getRecipes() {
return recipes;
}

This is the inverse side of the relationship, which means that changes to the relationships are persisted when the Recipe is persisted. The default behaviour of Hibernate with the above annotations is to add a column "category_id" to the Recipie table, which holds the id of the owning Category and has a foreign key constraint. All of this is of course handled by Hibernate, since we're using automatic schema updating.

However, in order to bind a Recipe to a Category, we're going to have to write a custom PropertyEditor that converts the incoming parameter "1" to the Category entity with id == 1. The recipe/edit.ftl view is modified to include the following selector:

<h4>Category</h4>
<select name="category">
<#list categories as c>
<option value="${c.id}"
<#if (recipe.category)?exists && (recipe.category.id == c.id)>selected="selected"</#if>>
${c.name}
</option>
</#list>
</select>

We also add all categories to the model, in RecipeController:

List<Category> categories = new Category().findAll();
...
model.put("categories", categories);

And here's the custom binder we need:

public void setAsText(String text) throws IllegalArgumentException {
Long id = Long.valueOf(text);
Category category = new Category();
category.setId(id);
setValue(category.load());
}

This binder needs to be registered in the RecipeController:

protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder)
throws Exception {
binder.registerCustomEditor(Category.class, new CategoryPropertyEditor());
}

This means that for all properties of class Category, use this binder to convert the incoming request parameter string to an object of the Category type. With this binder in place, we can keep using this form of handler method for storing a Recipe:

public ModelAndView store(HttpServletRequest request, HttpServletResponse response, Recipie recipie)
throws Exception {
if (recipie.getDate() == null) {
recipie.setDate(Calendar.getInstance());
}
recipie.store();
return new ModelAndView("redirect:list.htm");
}

The request parameters are automatically bound to a Recipe object, and we simply pass it to the
handler method and store it.

An clear advantage of Rails is that relationship binding is provided out of the box, whereas in Spring MVC we need to build a custom PorpertyEditor for that. Simple properties however, are automatically bound to the Recipie object.

This concludes the application part, a CRUD interface for recipies and categories. In part 5, we move on to testing.

Tuesday, September 12, 2006

Rolling with Spring and Hibernate, part 3: controller and view

So, now that we have a domain model with CRUD ability, we move forward to the controller and view parts. In the spirit of "convention over configuration", Spring 2.0 introduces a brand new URL mapper (the component responsible for determining what url (patterns) are handled by which controller): the ControllerClassNameHandlerMapping. Basically, it maps /foo/* requests too FooController, if FooController is a MultiActionController. We're going to write exactly such a RecipeController for the operations list, create, edit, store and delete.

For the views, I've chosen Freemarker, a fast and expressive template engine that has all the benefits of Velocity, the ability to use JSP taglibs and much more.

Additionally, I've chosen to add the OpenSessionInViewInterceptor, since all Rails relationships are lazy by default. It will allow Hibernate to load relations on the fly when needed, by keeping a session open during the request.

Rails controllers work exactly like the ControllerClassNameHandlerMapping, which is very handy since whenever you need an action /foo/doFunkyStuff, you just add that method to FooController and it will be exectued on those requests. Rails view are (always) .rhtml, which is Ruby scriptlets embedded in HTML, so both the handler mapping and the view configuration are things that work out of the box in Rails. Here's what our view and handler mapping configuration will look like (it goes into applicationContext-mvc.xml and cookbook-servet.xml, respectively):

<bean id="freeMarkerConfigurer" class="org.springframework...FreeMarkerConfigurer">
<property name="configLocation" value="/WEB-INF/classes/freemarker.properties" />
<property name="templateLoaderPath" value="/WEB-INF/freemarker" />
</bean>

<bean id="viewResolver" class="org.springframework...FreeMarkerViewResolver">
<property name="prefix" value="" />
<property name="suffix" value=".ftl" />
<property name="exposeSpringMacroHelpers" value="true" />
<property name="requestContextAttribute" value="rc" />
<property name="contentType" value="text/html; charset=UTF-8" />
</bean>

<bean id="openSessionInViewInterceptor" class="org.springframework...OpenSessionInViewInterceptor" />

There is a freemarker.properties which you can use to specify auto includes/imports, date formatting and some other things, but the defaults should do fine here.

Finally, the handler mapping:

<bean class="org.springframework...ControllerClassNameHandlerMapping">
<property name="interceptors" ref="openSessionInViewInterceptor">
</property>

<bean id="recipieController" class="se.petrix.cookbook.controller.RecipeController">

which is, as you can see, basically nothing. We simply rely on the class name, and add the OSIV interceptor to all handlers. The "interceptors" property is actually a list, but when you have a list with only one element, you can put it in a value or ref attribute.

We'll put our Freemarker templates in /WEB-INF/freemarker/recipe, and since we don't have any view scaffolding, we need to write them ourselves. One view for listing, and one view that we use for both edit and create. Freemarker does not handle null values, so we're going to make use of the "?if_exists" built-in, which expands to a GeneralPurposeNothing, a wrapper that usually has the meaning that you think it has, i.e. ${myList?if_exists} becomes an empty list, ${myString?if_exists} becomes an empty string and so on. Here's how we list all recipies:

<#list recipies?if_exists as r>
<tr>
<td>#{r.id}</td>
<td>${r.title?if_exists}</td>
<td>${r.description?if_exists}</td>
<td>${r.instructions?if_exists}</td>
<td>${(r.date.time)?if_exists?date}</td>
<td>${(r.category.name)?if_exists}</td>
<td><a href="${rc.contextPath}/recipie/edit.htm?id=#{r.id}">Edit</a></td>
<td><a href="${rc.contextPath}/recipie/delete.htm?id=#{r.id}">Delete</a></td>
</tr>
</#list>

Here you can see the date-formatter that works on a java.util.Date (?date). Another important thing is that Freemarker formats numbers by Locale when you use ${someNumber} ("1,000" in US locale vs. "1 000" in Swedish), but prints it as a mathematical number when you use #{someNumber} ("1000"). The "rc" varable is Spring's RequestContext, a wrapper around the HttpServletRequest that you can use for accessing the context path for example.

Note: as of Freemarker 2.3.7, the "?if_exists" builtin has been superceded by the shorthand notation "!".

Now there's only one thing left: web.xml. Again, Rails does not need one, but it's not a big deal, since you rarely make any big changes to it after the first few weeks of development, and you most likely already have a skeleton to start from (if you don't, you can use mine). It says "alright, we have a Spring servlet, which we want to hand *.htm requests to, and the Spring context is specified in the /WEB-INF/classes/applicationContext-*.xml files". As with all XML files in this example application, it has a corresponding XSD which smart editors can utilize to provide syntax checking an element and attribute completion.

Package the web app inside the source directory:

mvn war:inplace

The first time you run any Maven command it will download a large number of jars, many of which are plugins. It's all cached locally, so don't worry. On deploy, Hibernate will create your database schema for you.

AspectJ load-time weaving requires a parameter to be passed to the Java VM. This can be accomplished by setting the shell variable MAVEN_OPTS before starting Jetty:

export MAVEN_OPTS=-javaagent:src/main/webapp/WEB-INF/lib/aspectjweaver-1.5.2a.jar

Adapt to your shell of choice. Now we're ready to start the Jetty server:

mvn jetty:run

Watch the magic at http://localhost:8080/cookbook/recipe/list.htm :-)

The scan interval is set to 3 seconds, and since we're packaging the webapp inside the source directory, any changes to non-Java files are instantly available, and changes to Java files will trigger a context reload on recompilation (which your IDE should do for you). Try the old space-backspace-save trick to trigger a recompilation, and you should see a context reload.

In part 4, we'll add the Category model and relationship between Recipe and Category.

Monday, September 11, 2006

Rolling with Spring and Hibernate, part 2: the model

Most of the first part consisted of preparing the development environment, and while Rails clearly is faster here, the interesting part begins now, when we look at how much work goes into each actual modification of the application. Almost all of part 1 can be condensed into a more sophisticated Maven archetype.

The first thing we'll do now is to begin building our domain model. As I said, we'll use Hibernate with annotations as our ORM, and were going to let the model drive the database design. Hibernate is configured with url, driver class and so on, and additionally we enable the automatic schema updating from mapping metadata:

hibernate.hbm2ddl.auto=update

in hibernate.properties. Another useful setting is dumping formatted SQL to standard out, so that we can easily inspect the generated SQL:

hibernate.show_sql=true
hibernate.format_sql=true

A new feature of Spring 2.0 is the ability to wire collaborators into domain model objects on instantiation, using the @Configurable annotation and AspectJ load-time weaving. Were going to use this to inject a Hibernate SessionFactory into the domain model, allowing use to completely skip the DAO layer and use a syntax similar to ActiveRecord, with CRUD metods in the domain object. For simple application such as this one, we don't need any additional abstraction on top of Hibernate.

Populate the Recipe class with a few properties, and make it an @Entity:

@Entity
@Configurable(autowire=Autowire.BY_NAME)
public class Recipe {

String title;
...
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
...
}

Yes, we're missing an id, but we're going to build a BasicEntity base class that provides CRUD for both our Recipe and Category classes. The main point here is that you simply add a property to a Java class marked as @Entity, and Hibernate will modify the database schema on deploy. This is contrary to Rails, where you modify the schema by hand and get the model properties on the fly. For a simple model, either way is sufficient and roughly equivalent (they follow the DRY principle), but as an application grows in complexity you may want to diverge a little from the default behaviour.

The CRUD-providing base class looks like this:

@MappedSuperclass
public abstract class BasicEntity implements Serializable {

private Long id;
protected SessionFactory sessionFactory;

@Id
@GeneratedValue(strategy=GenerationType.AUTO)
public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

@Transient
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}

@Transient
protected Session getSession() {
return sessionFactory.getCurrentSession();
}

@Transient
protected Criteria getCriteria() {
return getSession().createCriteria(this.getClass());
}

@SuppressWarnings("unchecked")
@Transactional(readOnly=true)
public T load() {
getSession().refresh(this);
return (T) this;
}
...
// + methods for store, delete and findAll

}
There are many interesting things here: the @MappedSuperclass annotation allows us to use this as a base class for mapped entities, with the Id property being mapped in subclasses. We're using generics to make return values match the inherited class, a varargs parameter for relational properties to join (relations are lazy by default in Hibernate 3), and we're using the @Transactional annotation to specify that the load() method should be run in a transaction.

In other words, theres a lot going on here. But maybe the most important thing is the SessionFactory, which of course is the Hibernate interface through which you perform the actual database operations. On to the application context: here's what we need to inject a SessionFactory into all Recipe instances, even those created outside of our control, and to make all @Transactional methods transactional:

<bean id="transactionManager" class="org.springframework...HibernateTransactionManager">

<bean class="org.springframework...AnnotationBeanConfigurerAspect" method="aspectOf">

<bean class="org.springframework...AnnotationTransactionAspect" method="aspectOf">

<bean id="sessionFactory" class="org.springframework...AnnotationSessionFactoryBean">
<property name="annotatedClasses">
<list>
<value>se.petrix.cookbook.model.Recipe</value>
</list>
</property>
</bean>


In other words, we need a transaction manager (since @Transactional isn't tied to any particular transaction implementation), a SessionFactory of course, and finally the two AspectJ aspects that are applied to classes and methods with the @Configurable and @Transactional annotations. All of this goes into applicationContext-hibernate.xml. For the AnnotationBeanConfigurerAspect bean, we could use the shorter form:

<aop:spring-configured />

but since there's no corresponding short version for the transaction aspect (<tx:annotation-driven/> is for Spring AOP, not AspectJ...hopefully that'll change in the future). In general, Hibernate configuration could benefit in a major way from an XSD schema.

Comparing to Rails, we note that none of this is needed, since you don't get to choose/have to decide what transaction strategy or ORM solution you want. One annoying thing in Spring however is that you have to manually specifiy what classes should be mapped by Hibernate, even though they are all marked with @Entity. That's one area that Spring could improve upon Hibernate, by post-processing all classes in a package hierarchy specified by a wildcard pattern, for example. More on that in the last part.

The functionality of the BasicEntity class is provided by ActiveRecord in Rails, which your mapped domain objects inherit. This is a fair amount of overhead at this stage, on the other hand we could scale this by switching to injecting a complex business layer fairly easily, creating more layers in our application.

Finally we change the Recipe class to inherit from BasicEntity:

public class Recipe extends BasicEntity<Recipe> implements Serializable {

Note the parametrization!

Rolling with Spring and Hibernate, part 1: setup

Now that the Spring 2.0 release is imminent, and we're approaching the final version of JPA with Hibernate being the most prominent implementation, I though it would be interesting to see how the Recipies application know from the excellent "Rolling with Ruby on Rails" article from ONLamp.com could be built on this upcoming stack.

Note that I'm not trying to make neither Rails nor Spring/Hibernate (intentionally) look bad, I think both stacks are very interesting. This particular domain, very-simple-web-application-with-a-quick-start really should be considered Rails' home turf, and I'm trying to determine exactly where the overhead is major, where it's minor, and maybe even where Rails is trailing. I'm also going to point out a few areas where Spring could do better.

This first part is going to describe the development setup I'm using: tools, API:s etc.

I decided to use the following API components:
And these development tools:
WST and SpringIDE are crucial for smooth XML editing, offering code-completion and validation of everything from attribute values (according to XSD) to bean-name references.

Ok, so let's get this party started! First of all, we create a database using these commands in a MySQL promt:

create database 'cookbook' character set 'utf8';
grant all on cookbook.* to 'cookbook'@'localhost' identified by 'cookbook';

Maven lets us create the basic directory structure and a basic pom.xml by running the Quickstart archetype:

mvn archetype:create -DgroupId=se.petrix -DartifactId=cookbook

Unfortunately, a few important directories are missing from this, so we create them manually:

mkdir -p src/main/resources
mkdir -p src/test/resources
mkdir -p src/main/webapp/WEB-INF

The "resource" directories hold stuff that goes into the root of the classpath in the final package. We can also get rid of the App.java and AppTest.java files.

Next, we populate the pom.xml with the API components we've chosen. Rails, of course does not really offer a choice of ORM, templating engine etc, so this is a bit more work. A slightly more advanced archetype could make this a lot easier, by generating a pom.xml with a few more dependencies and common configuration options already in place. I won't go through the entire pom.xml here, but there are a few caveats:
  • We need to set the source and target levels of the Java compiler to 1.5 explicitly, Maven assumes java 1.4.
  • The Hibernate Annotations dependency information is a bit out of date, so we need to exclude the improper dependency and include the correct one.
  • The output directory, which is propagated to Eclipse, is set to inside the web app source folder, to make the feedback cycle as short as possible.

The short feedback cycle is one of Rails' strongest points, and due to the fact that we can't reload classes on the fly in Java - a very popular RFE - we need to reload the entire web app when making a change in a Java file. It's not as bad as it may sound though, reloading is fast and automatic. Changes to Freemarker templates require no reloading, and Spring 2.0 allows you to write beans in script languages such as Groovy, BeanShell or even Ruby, which don't need reloading either.

After this is done, we generate the Eclipse project metadata using Maven:

mvn eclipse:eclipse

One of the benefits of Maven is that you can generate project metadata for many of the biggest IDE's, such as Eclipse, Netbeans and IDEA. In general I think it would be safe to say that IDE support is a lot better for the Spring/Hibernate stack than for Rails, and Maven makes it easy to move between them.

In the next part, we'll start writing our domain model.