Moving from Spring's XML to Annotations in AppFuse
Last night, I did a spike on AppFuse to change XML to Spring annotations (@Repository, @Service and @Autowired) in its service and data modules. While I was able to accomplish everything in a few hours (including converting tests), I did run into a couple issues.
AbstractTransactionalJUnit4..Tests vs. AbstractTransactionalDataSource..Tests
I've switched from my favorite Spring class to the annotation-happy AbstractTransactionalJUnit4SpringContextTests. However, this has presented an issue: when using ATDSSCT, I was able to call endTransaction()
and startNewTransaction()
. With ATJ4SCT, this doesn't seem possible. Below is a screenshot of the diff on a test method in the JPA implementation of UserDaoTest:
On the right, you'll notice that I had to comment out @ExpectedException
to get the test to pass. This concerns me since this exception should be thrown. Is there a way to call endTransaction()
and startNewTransaction()
when subclassing AbstractTransactionalJUnit4SpringContextTests?
Instantiating GenericDao Implementations Programmatically
The second feature I tried to add is the ability to instantiate a GenericDao programatically rather than requiring a XML bean definition. In current versions of AppFuse, you can use the following bean definition to create a GenericDao for a model object.
<bean id="personDao" class="org.appfuse.dao.hibernate.GenericDaoHibernate"> <constructor-arg value="org.appfuse.tutorial.model.Person"/> <property name="sessionFactory" ref="sessionFactory"/> </bean>
When moving to a no-XML required architecture, it'd be nice to allow users to create GenericDao's programmatically. Below is the easiest way I've found to do this in a test:
GenericDao<User, Long> genericDao; @Autowired SessionFactory sessionFactory; @Before public void setUp() { genericDao = new GenericDaoHibernate<User, Long>(User.class); genericDao.setSessionFactory(sessionFactory); }
However, there's a couple problems with this. First of all, mixing constructor injection and setter injection probably isn't a good idea. Changing the constructor to take a SessionFactory solves this problem, but now all subclasses need to have a more verbose constructor:
@Autowired public UserDaoHibernate(SessionFactory sessionFactory) { super(User.class, sessionFactory); }
Whereas before they had:
public UserDaoHibernate() { super(User.class); }
In an ideal world, I could call new GenericDaoHibernate<User, Long>(User.class)
and the SessionFactory would be wired in auto-magically. Is this possible with Spring 2.5?
The 2nd problem this presents is your client code will now be dependent on an implementation rather than the interface. I don't know how to solve that one, but I'd love to figure out a way to create GenericDaos with no XML and no implementation details in the client. Any ideas are most welcome.
If you'd like to see all the changes I made in converting from XML to Annotations, please see this patch.