GenericDAO

Primeiro post depois de perder minha acc:

Eu vi em alguns posts uma discução sobre criar um dao generico. O problema é que ele não ficava tipado e haviam varios casts no codigo cliente.

Eu fiz uma solução aqui e gostaria de compartilhar:

Repositorio Generico

[code]public interface GenericRepository {
/**
* @param instance
*/
public void save(T instance);

/**
 * @param id
 * @return
 */
public T findById(Integer id);

/**
 * @return
 */
public List<T> findAll();

/**
 * @param begin
 * @param end
 * @return
 */
public List<T> findAll(Integer begin, Integer end);

/**
 * @param example
 * @return
 */
public List<T> findByExample(T example);

/**
 * @param example
 * @param begin
 * @param end
 * @return
 */
public List<T> findByExample(T example, Integer begin, Integer end);


/**
 * @param isntance
 */
public void remove(T isntance);

}[/code]

O repositorio Pessoa

[code]public interface PessoaRepository extends GenericRepository {

}
[/code]

O DAO generico, usando o hibernate template do Spring.

[code]public class GenericDAO extends HibernateDaoSupport implements GenericRepository {

private static final Log log = LogFactory.getLog(GenericDAO.class);
private final Class typeClass;

/**
 * @param argClass
 */
public GenericDAO(Class argClass) {
	typeClass = argClass;
}

/* (non-Javadoc)
 * @see com.navita.model.repository.GenericRepository#save(null)
 */
public void save(T instance) {
	log.debug("saving " + instance.getClass().getName() + " instance");
	try {
		getHibernateTemplate().saveOrUpdate(instance);
		log.debug("save successful");
	} catch (RuntimeException re) {
		log.error("save failed", re);
		throw re;
	}
	
}

/* (non-Javadoc)
 * @see com.navita.model.repository.GenericRepository#findById(java.lang.Long)
 */
public T findById(Integer id) {
	log.debug("getting " + typeClass + " instance with id: " + id);
	try {
		T instance = (T) getHibernateTemplate().get(typeClass, id); 
		return instance;
	} catch (RuntimeException re) {
		log.error("get failed", re);
		throw re;
	}
}

/* (non-Javadoc)
 * @see com.navita.model.repository.GenericRepository#findAll()
 */
public List<T> findAll() {
      log.debug("finding all " + typeClass.getName() + " instances");
      try {
          List<T> results = (List<T>) getHibernateTemplate().loadAll(typeClass);
          log.debug("findAll successful, result size: " + results.size());
          return results;
      } catch (RuntimeException re) {
          log.error("findAll failed", re);
          throw re;
      }
}



/* (non-Javadoc)
 * @see com.navita.model.repository.GenericRepository#findAll(java.lang.Integer, java.lang.Integer)
 */
public List<T> findAll(Integer begin, Integer end) {
      log.debug("finding all " + typeClass.getName() + " instances from: " + begin + " to: " + end);
      try {
    	  DetachedCriteria criteria = DetachedCriteria.forClass(typeClass);
          List<T> results = (List<T>) getHibernateTemplate().findByCriteria(criteria, begin, end);
          log.debug("findAll successful, result size: " + results.size());
          return results;
      } catch (RuntimeException re) {
          log.error("findAll failed", re);
          throw re;
      }
}

/* (non-Javadoc)
 * @see com.navita.model.repository.GenericRepository#findByExample(null)
 */
public List<T> findByExample(T example) {
	return findByExample(example, -1, -1);
}



/* (non-Javadoc)
 * @see com.navita.model.repository.GenericRepository#findByExample(T, java.lang.Integer, java.lang.Integer)
 */
public List<T> findByExample(T example, Integer begin, Integer end) {
      log.debug("finding " + example.getClass().getName() + " instance by example from: " + begin + " to: " + end);
      try {    	  
          List<T> results = (List<T>) getHibernateTemplate().findByExample(example, begin, end); 
          log.debug("find by example successful, result size: " + results.size());
          return results;
      } catch (RuntimeException re) {
          log.error("find by example failed", re);
          throw re;
      }
}

/* (non-Javadoc)
 * @see com.navita.model.repository.GenericRepository#remove(null)
 */
public void remove(T instance) {
	log.debug("deleting " + instance.getClass().getName() + " instance");
	try {
		getHibernateTemplate().delete(instance);
		log.debug("delete successful");
	} catch (RuntimeException re) {
		log.error("delete failed", re);
		throw re;
	}
}

}
[/code]

O DAO especifico da pessoa

[code]public class PessoaDAO extends GenericDAO implements PessoaRepository {

public PessoaDAO() {

	super(Pessoa.class);

}

}[/code]

Esse código resolve os metodos default para todos os daos. Caso tenha algum metodo com criterio de pesquisa, basta declara-lo no PessoaRepository e implementar no PessoaDAO.

Agora uma dúvida, eu tive que passar como arg no construtor do GenericDAO a classe específica para o hibernate template utilizar (typeClass). Isso somente para os metodos findById e para o findAll onde não existe uma instância de pessoa por exemplo.
Agluma ideia melhor?

Legal…

Tambem achei este artigo bem interessante.
http://www-128.ibm.com/developerworks/java/library/j-genericdao.html

achei bem legal. Isso tem recurso de java 5, não é?

Sim, Generics.

Eh bem elegante e tal, mas tem esse “problema” de usar java 5… aqui ainda tem muita coisa em 1.4, e nao vai ser possivel migrar. Tem algo do gênero pra 1.4?

Mais um artigo, esse da fonte:

http://blog.hibernate.org/cgi-bin/blosxom.cgi/2005/09/08#genericdao

Com IOC ficaria show de bola…

Sem Generics eu não imagino como ficaria…

Sem Generics eu não imagino como ficaria…[/quote]

Casting pra cá, casting pra lá…

Muito boa solução…

Achei muito bom.
Eu só não entendi porque tem que ter genérics.
Esse não indica que pode ser quaquer classe.
Não precisaria de cast do mesmo jeito ?

[quote=okara]Achei muito bom.
Eu só não entendi porque tem que ter genérics.
Esse não indica que pode ser quaquer classe.
Não precisaria de cast do mesmo jeito ?[/quote]

Não precisa de cast, para isso que servem os generics.
Eu crio minha classe generica usando um , mas nas outras classes como o PessoaDAO eu especifico que esse é na verdade uma .

Assim como eu declaro

Entendeu?

Se usa Generics, não precisa passar a classe persistente como argumento no contrutrutor.

Troca isso:

    private final Class typeClass;  
      
    /** 
     * @param argClass 
     */  
    public GenericDAO(Class argClass) {  
        typeClass = argClass;  
    }  

Por isso:

    private final Class&lt;T&gt; persistentClass;

    public GenericDao() {
        this.persistentClass = (Class&lt;T&gt;) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
    }

Você vai precisar disso: import java.lang.reflect.ParameterizedType;

Eu gostei muito dessa tua implementação, até vou testar mais tarde. Estava pensando agora em uma outra dúvida.
Adicionar um método na interface GenericDAO que implementa uma ordenação, invez de usar “query order by id”, isso simplificaria mais o código ainda a meu ver, usando collections ou algo do genero, a minha questão é qual é o menor custo computacional, a ordenação pelo sgbd ou pela vm?

(eu estou implementando sem uso de hibernate claro)

por exemplo eu invez de ter um método

getListOrderedById()

fazer algo tipo

getList().orderBy(“coluna_id”);