Eu esotu desenvolvendo o meu primeiro CRUD genérico em JPA e estou com uma dúvida que não estou conseguindo resolver,
para atualizar ou remove um objeto no JPA eu preciso encontra-lo primeiro pelo seu ID e depois atualiza-lo ou exclui-lo neh verdade?
O problema é que eu não estou conseguindo fazer a busca pelo ID usando o JPA
public T procurarPorId(Integer id) throws Exception {
T object = null;
try{
object = (T) em.find(object.getClass(), id);
return object;
}
catch(Exception e){
throw e;
}
finally {
em.close();
}
}
dá uma NullPointerException em T object = null; mas como estou usando generic eu não posso instânciar object e por isso dá uma NullPointerException.
Ricardo, se está usando Generics porque precisa converter o Generic em Objetc e retornar esse Object sendo que o seu método retorna um Generic?
Algo tão importante quanto isso, é se você já leu sobre o método find do EntityManager.
A classe que é informando no método find deve ser um @Entity e representa a entidade que desejas retornar, sendo assim, se faz necessário que informe o que está buscando. Creio que se quer algo tão genérico não deves usar o find, mas fazer como uma query qualquer.
Só para deixar claro o que eu quero dizer, se você envia uma classe “genérica” ao find, como ele vai descobrir qual tabela ele deve consultar através da PK? Por mágica que não será, concorda?
Uma sugestão, é você alterar a assinatura do seu método, assim:
public interface GenericDAO <T,ID extends Serializable> {
public Class<T>getObjectClass();
public T findById(ID id);
public T salvar(T object) ;
public T atualizar(T object);
public T excluir(T object);
public List<T> todos(String ordem);
}
Impl:
public class GenericDAOImp<T,ID extends Serializable> implements GenericDAO<T, ID> {
@PersistenceContext
private EntityManager entityManager;
private final Class<T> classePersistente;
public GenericDAOImp(){
this.classePersistente = (Class<T>)
((ParameterizedType)getClass().getGenericSuperclass())
.getActualTypeArguments()[0];
}
public Class<T> getClassePersistente() {
return classePersistente;
}
protected final Criteria criaCriteria() {
return criaSession().createCriteria(getClassePersistente());
}
public final Session criaSession() {
return (Session)getEntityManager().getDelegate();
}
public EntityManager getEntityManager() {
return entityManager;
}
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
@Override
public Class<T> getObjectClass() {
return this.classePersistente;
}
@Override
@Transactional(readOnly = false, propagation = Propagation.REQUIRED)
public T salvar(T object) {
getEntityManager().clear();
try {
getEntityManager().persist(object);
}catch(Exception e){
e.printStackTrace();
}
return object;
}
@SuppressWarnings("unchecked")
public List<T> todos(String ordem){
StringBuffer queryS = new StringBuffer("SELECT obj FROM "+classePersistente.getSimpleName()+" obj ");
if(ordem!=null){
queryS.append("order by "+ordem);
}
Query query = getEntityManager().createQuery(queryS.toString());
return query.getResultList();
}
@Override
@Transactional(readOnly = false, propagation = Propagation.REQUIRED)
public T atualizar(T object) {
getEntityManager().merge(object);
return null;
}
@Override
@Transactional(readOnly = false, propagation = Propagation.REQUIRED)
public T excluir(T object) {
try {
object = getEntityManager().merge(object);
getEntityManager().remove(object);
}catch(Exception e){
e.printStackTrace();
}
return null;
}
@Override
@Transactional(readOnly = false, propagation = Propagation.REQUIRED)
public T findById(ID id) {
return getEntityManager().find(getClassePersistente(), id);
}
Devemos entender que deu certo?
E o pessoal costuma utilizar um componente chamado JUnit para realização de testes.
É muito interessante, é uma API via Annotation e que você pode montar vários ambientes de testes.
Mas precisa de paciência e atenção para montar os testes.