[Resolvido] Retorno de Generic < >

Olá galera,
estou tentando criar uma classe que define a collection a ser utilizada e possui um método com o retorno do tipo dessa collection, algo mais ou menos assim:

public class CrudCliente<T extends Collection>  {
   public T getAllGenerico() {
        Collection x = new ArrayList();
        return x;
   }
}

Contudo eu recebo um erro dizendo que o retorno não é compatível com o tipo de retorno, gostaria de saber porque isso acontece e se há alguma forma de implementar oque eu quero.

Repare que no seu método você espera por um retorno de T.

public T getAllGenerico()

Entretanto você este tentando retornar uma collection

//Aqui você declara x como um objeto de classe Collection
 Collection x = new ArrayList();  
//E tenta retornar uma Collection quando o método espera que você retorne um objeto de classe T
 return x; 

Para arrumar isso existe duas opções:
1 - Você altera o retorno do método.
2 - Você retorna o que o método espera.

Como eu acho que você quer retornar uma Collection você poderia fazer:

//Você quer que seu método retorne uma Collection logo
public Collection getAllGenerico() {
   // Implemente seu método aqui.
}

Você quer fazer um CRUD para persistir um Objeto correto ?
Então por que no seu generic você tem uma relação de herança, a classe T herda Collection.
Não seria mais facil fazer apenas:

     public class CrudCliente<T>  {  
        public Collection<T> getAllGenerico() {  
             Collection<T> x = new ArrayList<T>();  
             return x;  
        }  
     }    

[quote=Heitor V]
Você quer fazer um CRUD para persistir um Objeto correto ?
Então por que no seu generic você tem uma relação de herança, a classe T herda Collection.
Não seria mais facil fazer apenas:

public class CrudCliente<T> { public Collection<T> getAllGenerico() { Collection<T> x = new ArrayList<T>(); return x; } } [/quote]
Sim eu entendo, mas nesse seu exemplo eu teria de realizar cast para utlizar uma implementação de collection

ArrayList lista = (ArrayList) new CrudCliente.getAllGenerico();

ou percorrer ela por completo atribuindo os valores para a implementação:

ArrayList lista = new ArrayList();
for (Object obj : new CrudCliente.getAllGenerico() ){
   lista.add(obj);
}

Oque procuro é uma forma de setar dinâmicamente uma Collection especifica antes ou durante a chamada do método, para que depois eu possa fazer algo assim (apenas como exemplo já que essa implementação abaixo não funciona)

ArrayList<Casa> lista = new CrudCliente<ArrayList<Casa>>.getAllGenerico();
TreeSet<Barco> lista = new CrudCliente<TreeSet<Barco>>.getAllGenerico();
LinkedList<Object> lista = new CrudCliente<LinkedList<Object>>.getAllGenerico();

Sem a necessidade de cast ou uma iteração completa pela Collection.

Bem me desculpe não tinha entendido o que você queria, agora que você explicou novamente ficou um pouco mais fácil.
Olha bem para sua classe, e responda: O método que fará a busca pelos diferentes objetos fará a mesma busca para todos?

ArrayList<Casa> lista = new CrudCliente<ArrayList<Casa>>.getAllGenerico();
TreeSet<Barco> lista = new CrudCliente<TreeSet<Barco>>.getAllGenerico();
LinkedList<Object> lista = new CrudCliente<LinkedList<Object>>.getAllGenerico();

Casa, barco e Object serão buscados do mesmo jeito, apenas um método realizara todas as buscas por todos os objetos ?
Eu não sei aonde você pretende buscar essas dados mas vamos supor que seja em um banco de dados MySql.
Então, Casa e Barco tem tabelas diferentes correto, logo tem SQL diferentes.

SELECT * FROM nome da tabela dos barcos/Casa;

Então como apenas um método saberá realizar isso?

Eu sei que não respondi sua dúvida, mas eu não vejo uma utilidade para sua classe…
Vamos partir do principio, aonde os dados serão guardados? Essa sua classe é realmente a melhor maneira de realizar essa busca?

Estou usando JPA com a API Criteria, meu método recebe a classe como parâmetro para realizar a busca no banco

public class CRUD <E extends Collection> {

   public E getAllGenerico(Class classe) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory(PU);
        EntityManager em = emf.createEntityManager();
        try {
            CriteriaBuilder cb = em.getCriteriaBuilder();
            CriteriaQuery cq = cb.createQuery(classe);
            Root raiz = cq.from(classe);
            cq.select(raiz);
            TypedQuery q = em.createQuery(cq);
            Collection elementos = q.getResultList();
            return elementos; // Erro, o tipo de retorno é E sendo que está tentando retornar Collection...porquê?
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        } finally {
            em.close();
        }
    }
    
     public static void main (String args[]){
          CRUD<ArrayList> crud = new CRUD<ArrayList>();
          ArrayList<Cliente> lista = crud.getAllGenerico(Cliente.class);
    }
}

Mas minha dúvida é especificamente sobre porquê, visto que meu generic “E” estende Collection e meu método retorna este mesmo generic, eu não consigo retornar uma Collection propriamente dita?

Tudo bem.
Olhe com atenção o que você usar para retornar o resultado de sua busca.

      TypedQuery q = em.createQuery(cq);  
      Collection elementos = q.getResultList(); //Retorna uma Lista, interface List.  
      return elementos;

Agora olhe o seu método

    public class CRUD <E extends Collection>
    public E getAllGenerico(Class classe);

O erro que você tem é que você não pode converter collection para o tipo generico E.
Como ja que o meu E é uma classe filha de collection?

O que acontece é que mesmo E sendo filha de collection ela não é, necessariamente, uma List, e se eu tentasse pedir um Set ?

     TreeSet<Barco> lista = new CrudCliente<TreeSet<Barco>>.getAllGenerico();

O que aconteceria é um erro, pois uma list não pode sofrer Cast para um Set. adicione um Cast no seu return e você vera exatamento isso.
Vou usar a primeira classe pois é mais simples… mas use a segunda tambem.

    public class CrudCliente<T extends Collection>  {  
       public T getAllGenerico() {  
            Collection x = new ArrayList();  
            return (T)x;  
       }  
    }  

Agora tenta executar o codigo acima, o do TreeSet, então o que aconteceu? Um erro, pois como eu ja disse uma List não pode ser Convertida para um Set, tanto que sua IDE deve dar um aviso quando você faz o cast no return, é por isso que mesmo herdando collection o seu retorno não é valido, pois a lista não é o tipo generico T.

Mas e se o meu tipo generico T for uma list?
Caso você faça o cast no return não havera problemas, mas sem o cast não ha como verificar isso na hora que você compila sua classe.

Pensei um uma solução que talvez funcione.

tenta assim

public class CrudCliente<E extends Collection<?>> {

	private Class<E> classeE;
	
	public E getAllGenerico(Class classe) {  
        EntityManagerFactory emf = Persistence.createEntityManagerFactory(PU);  
        EntityManager em = emf.createEntityManager();  
        try {  
            CriteriaBuilder cb = em.getCriteriaBuilder();  
            CriteriaQuery cq = cb.createQuery(classe);  
            Root raiz = cq.from(classe);  
            cq.select(raiz);  
            TypedQuery q = em.createQuery(cq);
            Collection elementos = q.getResultList();
            E e = classeE.newInstance();
            e.addAll(elementos);
            return e;  
        } catch (Exception e) {  
            e.printStackTrace();  
            return null;  
        } finally {  
            em.close();  
        }  
    } 

	public static void main(String args[]) {
		try{
			CrudCliente<ArrayList<Pessoa>> crud = new CrudCliente<>();
			ArrayList lista = crud.getAllGenerico(Pessoa.class);
		
			CrudCliente<TreeSet<Pessoa>> crud2 = new CrudCliente<>();
			TreeSet set = crud2.getAllGenerico(Pessoa.class);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

Entendi, e a sua solução funciona perfeitamente.
Muito obrigado pela ajuda !

Fico feliz em ter ajudado.
Faça varios testes nesse método, apenas para ter certeza, eu nunca tinha usado algo assim antes então não tenho 100% de certeza que funcione.