About this Tutorial
This tutorial will show you two things:
- You don't need to write DAOs if you just need generic CRUD functionality.
- How to write DAOs when you need custom functionality.
If you're new to JPA, you might want to read the JPA Reference Guide before starting this tutorial.
Table of Contents
- Setup your project to use JPA
- Register a personDao bean definition
- Create a DAO Test to test finder functionality
- Create a DAO Interface and implementation
- Run the DAO Test
Setup your project to use JPA
To change a newly-created project to use JPA instead of Hibernate (the default), you'll need to perform the following steps:
- Change the
<dao.framework>property in your
pom.xml(in a modular project, the top level pom.xml) to be jpa instead of hibernate.
- Delete the
hibernate.cfg.xmlfile in src/main/resources (in a modular project,
Register a personDao bean definition
AppFuse doesn't require you to write a DAO to persist a POJO. You can use the GenericDaoJpa class if all you need is CRUD on an object:
To register a personDao bean, open src/main/webapp/WEB-INF/applicationContext.xml (or core/src/main/resources/applicationContext.xml for a modular archetype) and add the following to it:
After doing this, you can use this bean on an object by adding the following setter method:
If you need more than just CRUD functionality, you'll want to continue reading below. If not, you can continue to Creating new Managers. This is a tutorial for creating Business Facades, which are similar to Session Facades, but don't use EJBs. These facades are used to provide communication from the front-end to the DAO layer.
Create a DAO Test to test finder functionality
Now you'll create a DaoTest to test that your DAO works. "Wait a minute," you say, "I haven't created a DAO!" You are correct. However, I've found that Test-Driven Development breeds higher quality software. For years, I thought write your test before your class was hogwash. It just seemed stupid. Then I tried it and I found that it works great. The only reason I do test-driven stuff now is because I've found it rapidly speeds up the process of software development.
To start, create a
PersonDaoTest.java class in your src/test/java/**/dao directory (or core/src/test/java/**/dao directory for a modular archetype). This class should extend
org.appfuse.dao.BaseDaoTestCase, a subclass of Spring's AbstractTransactionalJUnit4SpringContextTests. This parent class is used to load Spring's ApplicationContext (since Spring binds interfaces to implementations), and for (optionally) loading a .properties file that has the same name as your
*Test.class. In this example, if you put a
PersonDaoTest.properties file in src/test/resources/org/appfuse/tutorial/dao, this file's properties will be available via an "rb" variable.
The code you see above is what you need for a basic Spring integration test that initializes and configures an implementation of PersonDao. Spring will use autowiring to set the "personDao" bean as a dependency of this class.
Now you need test that the finder method works in your DAO. AppFuse uses JUnit 4, which allows you to indicate test methods with a @Test annotation. Add the following method to your PersonDaoTest.java file:
You'll notice that this method relies on pre-existing data in order to pass. The DbUnit Maven Plugin is used to populate the database with test data before the tests are run, so you can simply add the new table/record to the src/test/resources/sample-data.xml file (or core/src/test/resources/sample-data.xml for a modular archetype).
Since the PersonDao you're about to write includes CRUD functionality, you can also write a test to verify CRUD works properly.
In the above example, you can see that person.set*(value) is being called to populate the Person object before saving it. This is easy in this example, but it could get quite cumbersome if you're persisting an object with 10 required fields. This is why a ResourceBundle exists in
BaseDaoTestCase. Simply create a
PersonDaoTest.properties file in the same directory as
PersonDaoTest.java and define your property values inside it:
Then, rather than calling person.set* to populate your objects, you can use the
At this point, the
PersonDaoTest class won't compile yet because there is no
PersonDao.class in your classpath, you need to create it.
Create a DAO Interface and implementation
PersonDao.java interface in the src/main/java/**/dao (or core/src/main/java/**/dao for a modular archetype) directory and specify the finder method for any implementation classes.
Notice in the class above there is no exception on the method signature. This is due to the power of Spring and how it wraps Exceptions with RuntimeExceptions. At this point, you should be able to compile all your code using your IDE or mvn test-compile. However, if you try to run mvn test -Dtest=PersonDaoTest, you will get an error:
This is an error message from Spring - indicating that you need to specify a bean named "personDao". To do that you need to create the
PersonDaoJpa class that implements the finder method in
PersonDao. To do this, create a new class in src/main/java/**/dao/jpa (or _core/src/main/java/**/dao/jpa for the modular archetype) and name it
PersonDaoJpa.java. It should extend
GenericDaoJpa and implement
PersonDao. Javadocs eliminated for brevity.
Now, if you try to run mvn test -Dtest=PersonDaoTest, it should pass. The
@Repository annotation indicates this is a Spring bean. The following XML (in your applicationContext.xml file) scans for classes with these annotations. If you are writing your own Dao and Dao interface, be sure to comment out or remove the reference to the generic Dao in the
applicationContext.xml file in src/main/webapp/WEB-INF (or core/src/main/resources for a modular archetype).
If you don't like annotations, you can also use XML. To do this, you need to configure Spring so it knows that
PersonDaoJpa is the implementation of
PersonDao. Open the
applicationContext.xml file in src/main/webapp/WEB-INF (or core/src/main/resources for a modular archetype) and add the following XML to it:
Run the DAO Test
Save all your edited files and try running mvn test -Dtest=PersonDaoTest one more time.
Yeah Baby, Yeah:
Total time: 7.473s
Next Up: Part II: Creating new Managers - A HowTo for creating Business Facades, which are similar to Session Facades, but don't use EJBs. These facades are used to provide communication from the front-end to the DAO layer.