Sunday, September 25, 2005

On JSF, Struts, & Spring Part Deux

After a Saturday of messing around with Spring, JSF, & Hibernate I have a nice little application that does nothing more than retrieve an object from my local PostgreSQL database and display the value in a web page. While the end result isn't very exciting there is a whole symphony of integration going on under the covers.

Hibernate and Spring

I first created a couple business domain classes that use the latest and greatest Hibernate/EJB3 Java 5 annotations to describe how they map to database entities. This is currently supported in Hibernate 3.1 beta 3 so I didn't really expect to be able to use this stuff once I got to integrating it with Spring. I assumed I'd have to either write Hibernate mappings in XML or maybe integrate XDoclet to generate the mappings. Well to my surprise Spring has org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean!! So Spring was good to go! All I had to do was declare the sessionFactory and the transactionManager that I wanted in applicationContext.xml. I still haven't figured out a way to get it to autodiscover the annotated business model so I had to manually list the two classes but that wasn't too big of a problem.

I then moved on to creating a subclass of Spring's HibernateDaoSupport class and configuring it in applicationContext.xml where I learned about the declarative transaction management features of Spring. In this XML file I was able to wire together the DAO, the Hibernate sessionFactory, the transactionManager and indicate which DAO methods require a transaction. This simplified the code in the DAO by injecting the necessary Hibernate Session and Transactions at runtime. But this comes at the cost of using a HibernateDaoSupport method called getHibernateTemplate() whose returned object basically delegates to the injected Hibernate session and turns Hibernate exceptions into unchecked exceptions. This also has the unfortunate side effect of burying the native Hibernate API. I don't really care for that idea too much but it's a tradeoff for not having to manage session and transaction resources manually.

So I then created a little JUnit test, used the FileSystemXmlApplicationContext to start up Spring and then used the context to get the configured DAO from Spring and called a method. Everything worked as expected.

Spring and JSF

Next it came time to integrate JSF. This became a little more time consuming. First of all I needed to figure out how to initialize all the Spring stuff within a web application which in turn initializes all the Hibernate stuff. It was actually fairly simple. I only had to configure a listener in the web.xml file for org.springframework.web.context.ContextLoaderListener. Also by using context-param in web.xml I was able to tell this ContextLoaderListener instance where to find my spring applicationContext.xml files.

Secondly, JSF has its own Dependency Injection framework for configuring backing beans that have request, session or application scope and it was unclear to me how to integrate the two dependency injection frameworks i.e., If my DAO and Facade/Service classes are configured with Spring how would I go about injecting these instances into a JSF backing bean? Well as it turns out I can't. Not yet anyway. There is a little project appropriately enough named "jsf-spring" that aims to transparently aggregate these two frameworks. It's in beta. But Spring has a supporting class called FacesContextUtils which allows me to fetch an instance of WebApplicationContext (with the current FacesContext as a parameter). I can then use that Spring context object to fetch the DAO (or more typically a facade class) to do the work I need. Given all this dependency injection stuff this manual fetching of context objects and service objects seems like a very odd hack and is more like calling a singleton getInstance method. But it works and I was able to tie the business layer to the presentation layer.

Summary

So there you go, a display-only Spring/Hibernate/JSF application. It was a good lesson in making all the pieces work together. In the end I look at all this plumbing and I'm a bit surprised how simple and difficult it was to get everything going. The Spring stuff is well documented on the web and was easy to get going with Hibernate. But answers to my questions about adding JSF to the mix were a little harder to come by. I suspect the future holds a stronger integration for Spring and JSF (perhaps you can just use Spring as a replacement for the JSF injection framework) and I can see Java 5 annotations becoming more prevalent in Spring so that you don't have to write all that XML. Annotations work great for Hibernate so I don't see why they wouldn't work well for Spring too.

No comments: