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.
hi Matt,
did you try the Spring testing framework? I've used in my last project and it seems to me that it really eases the process of performing integration testing... this is the url if you haven't seen it:
http://static.springframework.org/spring/docs/2.5.x/reference/testing.html#testcontext-tx
Posted by Patria on November 04, 2008 at 07:44 PM MST #
hi!!!
i'm in the same case i have an abstractDao:
and my custom impl are like:
and finally in the test case:
I have some services that depends of this Dao and I have with JUnit4 like this:
Maybe this be useful for you, i'll hope so...
I don't have inconvenient with this way...
Regards
neodevelop
Posted by neodevelop on November 04, 2008 at 07:51 PM MST #
Posted by Jordi Bunster on November 04, 2008 at 09:25 PM MST #
Posted by Matt Raible on November 04, 2008 at 11:13 PM MST #
Matt,
For programmatic creation and autowiring in combination, you can use @Configurable along with @Autowired, such as:
In the Application Context configuration, you'll need to add the 'load-time-weaver' element in addition to 'annotation-config', and you'll need to provide a prototype-scoped bean whose type matches the programmatically created objects:
There are a couple other requirements (AspectJ JARs, etc.) as described in the Spring 2.5.x Reference Documentation.
Regards,
Mark
Posted by Mark Fisher on November 04, 2008 at 11:43 PM MST #
Posted by Lukas Krecan on November 05, 2008 at 09:18 AM MST #
Hi Matt,
I've been meaning to try this, but haven't gotten around to it. To address the issue of client code depending on the implementation class, I think one possibility would be to eliminate the constructor params from the generic DAO. If Spring's autowiring goes as far as inferring the type parameters (see Spring's GenericTypeResolver) then you might be able to obtain the params like this:
Do you think this would work? I'd be interested to know if anybody has tried it.
Chris.
Posted by Chris Herron on November 05, 2008 at 04:06 PM MST #
Posted by Marc on November 29, 2008 at 04:14 PM MST #
Posted by Matt Raible on December 10, 2008 at 04:38 PM MST #
Posted by Marc on December 10, 2008 at 04:44 PM MST #
Matt
Do you have any plans to switch client side validation to something annotation based?
Here is a good example in case you are curious.
http://wheelersoftware.com/articles/spring-bean-validation-framework.html
Posted by Alex on January 13, 2009 at 12:39 AM MST #
@Alex - I don't mind switching to a annotation-based validation solution, but I'm not too keen on putting framework-specific annotations in model objects. I'd prefer to use standard annotations like those provided with JSR 303.
Also, your solution doesn't seem to provide client-side validation whereas AppFuse's current solution (Commons Validator for Spring MVC) provides both client and server-side validation.
Posted by Matt Raible on January 13, 2009 at 01:01 AM MST #
Posted by Christian Decker on January 14, 2009 at 08:09 PM MST #
Posted by tibi on August 06, 2009 at 08:03 PM MDT #