Criando GenericDAO e DAOFactory em poucos passos

Ola pessoal,

No post de hoje vamos ver como criar genericDAO e DAOFactory  em poucos passos. O objetivo maior aqui é colocar a mão na massa. Os conceitos DAO Design Pattern não serão abordados, pois o que não falta é explicação na internet sobre o assunto. Vou considerar que você sabe conceitualmente um DAO, mas que nunca implementou  de forma genérica.

Lets go…

 

Primeiro passo

Cria a interface GenericDAO :

public interface GenericDAO<T,Type extends Serializable> {

void beginTransaction();

void commitTransaction();

void save(T entity);

void delete (T entity);

List<T> listAll();

}

O código acima usa apenas o recurso de generics do Java 5, deixando a interface que extends dizer qual será o tipo para T e o para Type.

O que significa cada um?

Simples: o T será a classe, ou seja, a entidade. O Type representará o tipo que usaremos para o Id da entidade. Você pode estar se perguntando pq a letra T e a palavra type. Apenas segui uma convenção, mas poderia ser qualquer outra letra ou nome.

Agora precisamos criar a interface dos nossos DAO, que nesse caso teremos as seguintes interfaces: ClientDAO e AccountDAO.

public interface AccountDAO extends GenericDAO<Account, Long>{

}

public interface ClientDAO extends GenericDAO<Client, Long> {

}

Observe que nas nossas interfaces é que definimos para qual entidade ela está associada e qual será o tipo do nosso ID.

É nessa interface que colocamos os métodos específicos para o nosso DAO.

Abstract HibernateDAO

Criaremos uma classe abstract que vai implementar o métodos abstract da interface GenericDAO. E nossas classes concentras vão extends a HibernateDAO como veremos a seguir. Mas antes disso precisamos criar uma classe utilitária que chamei de HibernateUtil, que terá o método para obtermos a sessão, iniciar a transação, commit, etc.

public class HibernateUtil {

private static SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();

private static ThreadLocal<Session> threadLocal = new ThreadLocal<Session>();

public static Session getSession() {

Session session = threadLocal.get();

if (session == null) {

session = sessionFactory.openSession();

threadLocal.set(session);

}

return session;

}

public static void beginTransaction() {

getSession().beginTransaction();

}

 public static void commitTransaction() {

getSession().getTransaction().commit();

public static void rollBackTransaction() {

getSession().getTransaction().rollback();

}

public static void closeSession() {

getSession().close();

}

}

E na classe HibernateDao temos o código a seguir:

public abstract class HibernateDAO<T, Type extends Serializable> implements GenericDAO<T, Type>{

private Class<T> persistentClass;

public HibernateDAO(Class persistentClass) {

super();

this.persistentClass = persistentClass;

}

@Override

public void beginTransaction() {

HibernateUtil.beginTransaction();

}

@Override

public void commitTransaction() {

HibernateUtil.commitTransaction();

}

@Override

public void save(T entity) {

HibernateUtil.getSession().saveOrUpdate(entity);

}

@Override

public void delete(T entity) {

HibernateUtil.getSession().delete(entity);

}

@Override

public List<T> listAll() {

HibernateUtil.beginTransaction();

Criteria criteria = HibernateUtil.getSession().createCriteria(persistentClass);

return criteria.list();

}

}

Observe que implementamos todos os métodos da GenericDAO, assim a classe que extends já tem a implementation done, ou seja, aquilo que é comum para qualquer  classe DAO já vai estar implementado e disponível na classe pai.

Concrete DAO

Agora vamos criar a classe concreta que terá a implementação específica para cada DAO.

class HibernateClientDAO extends HibernateDAO<Client, Long> implements  ClientDAO {

public HibernateClientDAO(){

//                           we passing the entity for super class

super(Client.class);

}

}

Como não temos nada de específico para implementar da interface ClientDAO deixaremos o código assim. Observe que no construtor passei qual será o tipo T, que nesse caso será a class do Client.

DAOFactory

Agora vamos criar um DAOFactory que será responsável por criar as instâncias das classes Hibernate. A classe DAOFactory será abstract e tendo apenas um método implementado que será o getFactory, o qual terá como objetivo simplesmente de retornar uma instância da classe.

public abstract class DAOFactory {

private static final Class FACTORY_CLASS = HibernateDAOFactory.class;

public static DAOFactory getFactory(){

try {

return (DAOFactory) FACTORY_CLASS.newInstance();

} catch (InstantiationException e) {

// TODO Auto-generated catch block

throw new RuntimeException();

} catch (IllegalAccessException e) {

// TODO Auto-generated catch block

throw new RuntimeException();

}

}

public abstract ClientDAO getClientDAO();

public abstract AccountDAO getAccountDAO();

}

Em seguida adicionamos os métodos que retornam a instância para as classes que implementam as interfaces ClientDAO e AccountDAO.

Agora teremos uma classe que implementa os métodos do DAOFactory, que será a classe HibernateDAOFactory.

public class HibernateDAOFactory  extends DAOFactory{

@Override

public ClientDAO getClientDAO() {

return new HibernateClientDAO();

}

@Override

public AccountDAO getAccountDAO() {

return new HibernateAccountDAO();

}

}

Observe que apenas instanciamos as classes para cada DAO. Agora vamos criar  HibernateAccountDAO

class HibernateAccountDAO extends HibernateDAO<Account, Long> implements AccountDAO {

public HibernateAccountDAO() {

super(Account.class);

}

}

E para testar, criaremos uma classe com o método main:

public class MainBank {

public static void main(String[] args) {

//                           getting instance of the factory

DAOFactory daoFactory = DAOFactory.getFactory();

//                           getting intance of clientDAO and starting transaction

daoFactory.getClientDAO().beginTransaction();

ClientDAO clientDAO = daoFactory.getClientDAO();

Client client = new Client();

client.setName(“Camilo Lopes”);

//                           creating object of the entity

Account checkigAccount = new Account();

checkigAccount.setAccountType(AccountType.CHECKING_ACCOUNT);

//                           associate acocunt with the client

checkigAccount.setClient(client);

//                           money available in account

checkigAccount.setBalance(BigDecimal.ONE);

client.getAccount().add(checkigAccount);

//                           saveing in hibernate session

clientDAO.save(client);

AccountDAO accountDAO = daoFactory.getAccountDAO();

accountDAO.save(checkigAccount);

//                           commit

clientDAO.commitTransaction();

}

}

Resultado

É isso ai pessoal, espero que tenham gostado. Vou ficando por aqui. 

See ya!!!

7 comentários em “Criando GenericDAO e DAOFactory em poucos passos”

    1. No momento que vc precisa obter a sessão, iniciar/commit a transação. Conforme pode ser vista na classe public abstract class HibernateDAO

  1. Seu blog é muito bom, mas infelizmente a formatação de códigos ainda não é boa e atrapalha um pouco. Talvez seja uma limitação do tema.
    Com relação ao post, o delete() é assim mesmo ?
    Eu tive pequenos problemas utilizando esse getSession().
    Eu tinha alguns registros e fazia alterações em alguns, mas quando buscava novamente os registros vinham os antigos e não os atualizados, mesmo commitando e fechando sessão. Tanto que algumas vezes vinham atualizados. hehehe. Eu verifiquei que isso ocorria por causa do ThreadLocal, mesmo fechando as sessões ele pegava uma antiga com dados antigos.
    Resolvi não usa-lo.
    Fiz da forma abaixo que resolveu:

    private Session session;

    public static Session getSession() {
    if (session == null || !session.isOpen()) {
    session = sessionFactory.openSession();
    }
    return session;
    }

    Ainda não notei problemas com essa forma.

    Abraço !

    1. olá Wendel,

      Essa formatação dos códigos é uma novela. Eu usava um plugin, só que é ruim, pq quando eles nao sao mais atualizados e eu removo ou surge um bug e eu n sabia e atualizo, dai acabava zuando tudo. E desistir do plugin, hoje uso as marcacoes simples do wordpress que não é bem o que eu queria, mas pelo menos resolvi o problema de não quebrar mais como os plugins me deixavam na mão.

      Sobre o problema, eu tive algo do tipo com o Hibernate 4, no Hibernate 3 não tive esse problema não.

      abracos,

  2. Fala cara, eu sou desenvolvedor .NET e estou estudando Java. Neste exemplo, não daria para fazer a classe
    public abstract class HibernateDAO implements GenericDAO concreta e usá-la para fazer a persistência?. Tipo:
    HibernateDAO clientDAO = new HibernateDAO();
    clientDAO.save(client);?
    Valeu.

    1. olá Rafael,
      Sim nada impede. Mas, pq eu faria isso? Ela já faz a persistencia a partir da entidade. Pelo que entendi o que você sugeriu não deixa a classe generica para tratar qualquer entidade.

      abraco, obrigado por comentar.

  3. primeiramente parabéns pelo post…

    Sua divisão entre interfaces e classes primeiramente me causou um certo susto, pensei: “Meu Deus! Quanta Classes estou criando!”, depois eu vi o quanto isso deixou mais legível meu projeto, realmente nos ajudou muito!

    Achei um errinho no meio do sua classe HibernateDAO, o método delete está executando: HibernateUtil.getSession().save(entity); ao invés de HibernateUtil.getSession().delete(entity);

    Um grande abraço!

Deixe um comentário

O seu endereço de e-mail não será publicado.