A properly designed mid sized Java application should use both - ORM to set up the bridge between the OO application classes and the relational tables, with DAO to ensure a clean separation between the domain objects and the persistence layer. The DAO implementation provides the facades which the business/domain model uses, and enables a seamless switching of the persistence layer downstream. Hence whatever the size of the project, the DAO pattern offers one of the basic tenets of OO design - separation of concerns.
While the DAO offers a comfortable switch on the persistence/ORM layer underneath, the application can ensure a flexible DAO layer implementation by applying yet another level of indirection. Separate the abstraction from the implementation (aha! the Bridge), and you have a generic contract for your application to play with ..
public abstract class DAOBase<T extends DTOBase> {
private DAOImplBase<T> m_impl; // the underlying implementation
...
...
With the number of growing vendors offering you the best of the breed DAO solutions (BTW Firestorm from CodeFutures is really cool), this approach can give you the flexibility of switching your DAO implementation.
The application DAOs fit in the hierarchy on the abstraction side, while the various implementations (Firestorm, Hibernate etc.) subclass from the
DAOImplBase
.// application DAO
public class EmployeeDAO<T extends DTOBase> extends DAOBase<T> {
...
// DAO implementation for JDBC
public class DAOJDBCImpl<T extends DTOBase> extends DAOImplBase<T> {
...
With the usual factories and utilities in place, finally the client code looks like the following:
// make the DAO
EmployeeDAO<Employee> e =
DAOFactory.getDAOFactory(DAOFactory.DAOImplType.JDBC).getEmployeeDAO();
// make the criteria
ICriteria cri = new SimpleCriteria("employee_id = 10");
// get 'em
List<Employee> es = e.read(cri, Employee.class);