I use something similar to what was indicated by @Cassio Danilo. But it is sometimes interesting that a DAO is implemented both via JPA and AdHoc (JDBC).
My suggestion is as follows:
Create an interface to DAO that suggests the main interaction methods with the entity (CRUD)
Create an abstract support class for each implementation type: JPA and AdHoc.
It would look like this:
Dao.class
public interface Dao<E extends Serializable, I> {
E consultarPorId(I id);
void inserir(E entity);
E atualizar(E entity);
void excluir(E entity);
List<E> consultarTodos();
}
AbstractJPADao.class
@Named
@Transactional(propagation = Propagation.MANDATORY)
public abstract class AbstractJPADao<E extends Serializable, I> extends AbstractJPASupport implements
Dao<E, I> {
private final Class<E> entityClass;
protected AbstractJPADao(Class<E> entityClass) {
this.entityClass = entityClass;
}
public CriteriaQuery<E> getCriteriaQuery() {
return this.getEntityManager().getCriteriaBuilder().createQuery(entityClass);
}
@Override
public void excluir(E entity) {
this.getEntityManager().remove(entity);
}
@SuppressWarnings("unchecked")
@Override
public List<E> consultarTodos() {
return this.getEntityManager().createQuery(
String.format("from %s", this.entityClass.getName()))
.getResultList();
}
@Override
public E consultarPorId(I id) {
return this.getEntityManager().find(entityClass, id);
}
@Override
public void inserir(E entity) {
this.getEntityManager().persist(entity);
}
@Override
public E atualizar(E entity) {
return this.getEntityManager().merge(entity);
}
}
AbstractJPASupport.class
@Named
@Transactional(propagation = Propagation.MANDATORY)
public abstract class AbstractJPASupport {
private EntityManager entityManager;
public AbstractJPASupport() {
}
public CriteriaBuilder getCriteriaBuilder() {
return entityManager.getCriteriaBuilder();
}
public EntityManager getEntityManager() {
return entityManager;
}
@PersistenceContext
@Inject
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
@PostConstruct
protected void init() {
checkState(this.entityManager != null,
"Atencao! Entity Manager nao inicializado.");
}
}
Watch out for the detail of @Transactional(propagation = Propagation.MANDATORY)
. If you are using Spring, it is an interesting way to ensure a non-functional requirement for your DAO not to run outside of a transacted environment.
Now, support for JDBC implementation:
AbstractJDBCDao.class
@Named
@Transactional(propagation = Propagation.MANDATORY)
public abstract class AbstractJDBCDao {
@Inject
private DataSource dataSource;
private NamedParameterJdbcTemplate jdbcTemplate;
private SimpleJdbcCall simpleJdbcCall;
private SimpleJdbcInsert simpleJdbcInsert;
public AbstractJDBCDao() {
}
@PostConstruct
protected final void init() {
checkState(this.dataSource != null,
"Atencao! DataSource nao inicializado.");
final JdbcTemplate rootJdbcTemplate = new JdbcTemplate(dataSource);
this.jdbcTemplate = new NamedParameterJdbcTemplate(rootJdbcTemplate);
this.simpleJdbcCall = new SimpleJdbcCall(rootJdbcTemplate);
this.simpleJdbcInsert = new SimpleJdbcInsert(rootJdbcTemplate);
}
public final void setDataSource(final DataSource dataSource) {
this.dataSource = dataSource;
}
protected final NamedParameterJdbcTemplate getJdbcTemplate() {
return jdbcTemplate;
}
protected final SimpleJdbcCall getSimpleJdbcCall() {
return simpleJdbcCall;
}
protected final SimpleJdbcInsert getSimpleJdbcInsert() {
return simpleJdbcInsert;
}
}
This implementation is based on Spring JDBC. Can be adapted to other frameworks . But the idea is to suggest that your data layer can implement more than one form of data access depending on your scenario.
I have made available in GitHub a project that can be used as a reference to work with Spring + JPA + JDBC using Profile
s to determine the type of data layer that will be used in the project. It is for reference only. If you have something to put, please leave it in the comments.