Problema dificil com tipologias (o coisa chata esses <T> do java)

Bom pessoal, estou tendo um problema com tipologia … e esta dificil de resolver, se alguem puder por favor me ajuda…

eu tenho um método, que tem 2 parametros… o 1° tem que ser uma classe do tipo T onde T assina IEntitySignature, e o segundo parametro é uma coleção de tipo também T … é imperativo, que tanto a classe como a coleção sejam da mesma entidade. Este método é parte dum repositorio de entidades, que persiste o banco de dados.

[code] public <E extends IEntitySignature> boolean contaisAll(Class<E> entityClass,Collection<E> entitys) {
return DataBase.getCurrentEntityRepository(entityClass).contaisAll(entitys);
}
//…

//Exemplo de uso:
Collection<Aluno> alunos = getListaParticularDeAlunosX();
boolean thisListIsPersistent = contaisAll(Aluno.class,alunos);[/code]

eu tenho 1 objeto, que guarda coleções de entidades… esse objeto é um manager, que organiza bem direitinho as coleções… ele separa as entidades por suas classes, em coleções internas…

Neste objeto os métodos relevantes ao meu problema são
1°) método que retorna um Iterator de classes, que são as classes das entidades… todas as classes deste iterator assinam a interface IEntitySignature
2°) método que retorna uma coleção de entidades de uma classe especifica… todas as entidades da coleção são do mesmo tipo da classe enviada
3°) método que adciona uma entidade ao manage… ele internamente busca a coleção da classe q a entidade pertence, e a coloca nesta coleção.

[code] public Iterator<Class<? extends IEntitySignature>> getEntityClasses() {
return collectionManager.keySet().iterator();
}

public &lt;T extends IEntitySignature&gt; Collection&lt;T&gt; getEntityCollection(Class&lt;T&gt; forThisClass) {
	return (Collection&lt;T&gt;)collectionManager.get(forThisClass);
}

public void addEntity(IEntitySignature entity) {
	if (!contaisCollectionFor(entity)) createCollectionFor(entity);
	getCollection(entity).add(entity);
}

//exemplo de uso (dentro do objeto, só existe 1 coleção para cada tipo de classe)
//…
objManager.addEntity(aluno1); //adciona na coleção de alunos.
objManager.addEntity(curso1); //adciona na coleção de cursos.
objManager.addEntity(aluno2); //adciona na coleção de alunos.
objManager.addEntity(aluno4); //adciona na coleção de alunos.

//Percorre a lista de coleções
for (Class classe: objManager.getEntityClasses() {
System.out.println(“Os “+ classe.getName() +” são:”);
//Percorre cada entidade dentro da coleção
for (Object entity : getEntityCollection(classe) ) {
System.out.println(entity.toString());
}
}
//o resultado do console será:

/**
Os model.entity.Aluno são:
João da silva
João dos santos
José da silva

Os model.entity.Curso são:
Ciências da computação
*/
[/code]

Bom meu problema esta no seguinte uso, estou implementado no repositorio um método, que pega um Manage destes de coleções…
Verifica quais classes ele contem… e manda cada coleção de cada classe para seu devido método…

Ele deveria funcionar assim
1 - pegar a lista de classes contidas no manager (são Keys para buscar as coleções)
2 - Para cada uma das chaves fazer o seguinte
. 2.1 - buscar a coleção daquela calsse
. 2.2 - testar se existe cada uma das coleções usando do repositorio contaisAll(classe,collection)
. 2.3 - se qualquer coleção retornar false através do contaisAll(classe,collection), parar o loop, e retornar que false.
3 - retornar verdade caso todas as coleções estiverem continas no repositorio.

Meu problema é o seguinte… getEntityClasses(); retorna apenas classes que implementam IEntitySignature
se eu fizer getEntityCollection(classe) de qualquer uma das classes vou objetar a sua coleção… porem! não consigo pegar a lista, de classes, percorrer a lista, e mandar a coleção para cada containsAll() … ele fala que os tipos não são compativeis…

public boolean contaisAll(EntityCollectionManager manager) { boolean contais = false; Iterator&lt;Class&gt;&lt;? extends IEntitySignature&gt;&gt; entityClassList = manager.getEntityClasses(); boolean moreTeste = entityClassList.hasNext(); while(moreTeste) { Class&lt;? extends IEntitySignature&gt; entityClass = entityClassList.next(); contais = contaisAll(entityClass, manager.getEntityCollection(entityClass)); //se não contiver a coleção, ou se não houver mais listas ele sai do loop moreTeste = contais && entityClassList.hasNext(); } return contais; }

O problema esta que… contaisAll(entityClass, manager.getEntityCollection(entityClass)); não é acieto pelo compilador…
Ele normalmente deveria aceitar… visto que contaisAll(Class<T>,Collection<T> ) exige classe e coleção do mesmo tipo, o que é verdade
quando faço manager.getEntityCollection(entityClass) recebo uma coleção do mesmo tipo de entityClass…

a unica falha esta em…"entityClass" é do tipo <? extends IEntitySignature> ou seja… é um tipo generico… invalidado a operação…
Eu não tenho como saber qual classe ta vindo, a não ser em tempo de execução… não sei como fazer um caster… sem saber exatamente qual classe vai vim…

Alguem me ajuda plix!!!

Lavieri:

Tudo isso está na classe *Manager, certo ? Defina a classe como EntityCollectionManager e
defina os métodos em função do parametro da classe,
e não em cada um dos métodos.

+1 coisa, no método containsAll(EntityCollectionManager), por que não usa o “enhanced for” ? O código fica bem mais limpo

Jorge

[quote=Jorge Diz]Lavieri:

Tudo isso está na classe *Manager, certo ? Defina a classe como EntityCollectionManager e
defina os métodos em função do parametro da classe,
e não em cada um dos métodos.

+1 coisa, no método containsAll(EntityCollectionManager), por que não usa o “enhanced for” ? O código fica bem mais limpo

Jorge

[/quote]

Noop… são 3 classes ai em questão…

1° se chama DataBase… ela tem funções estaticas, é uma classe de configuração, nela esta contida todos os reposiotorios do meu sistema… Por exemplo, se eu quiser resgatar o repositorio de alunos eu faço DataBase.getCurrentEntityRepository(Aluno.class) … e o repositorio de alunos sabe como tratar as entidades alunos… com esse repositorio eu tenho acesso a todas as funções como add, remove, update, etc etc etc …

2° se chama Repositories… ela é um atalho da 1° classe… através dela, eu consigo invocar os métodos dos repositorios sem ter q ficar passando a classe… para adcionar um aluno, por exemplo, basta fazer… repositories.add(aluno1) … o que esta classe faz é simples… ela busca o repositorio correto fazendo DataBase.getCurrentEntityRepository(aluno1.getClass).add(aluno1) … é basicamento isso que ela faz, ala me poupa de chamar o repositorio separado, e funciona como um repositorio generico…

3° se chama EntityCollectionManager … esta classe organiza coleções… c eu der um manager.add(aluno1) e manager.add(curso3) e manager.add(aluno2) e manager.add(matricula2) … ele vai guardar cada qual em sua coleção correspondente… c eu fizer … manager.getEntityCollection(Aluno.class) ele vai me voltar uma Collection só com o aluno1 e aluno2 … posso fazer o mesmo pra curso e matriculas… posso tb pedir a lista de entidades contidas no manager, esta lista são todas de Classes que extende a assinatura de entidade…

Enfim … desta forma eu estou querendo implementar, na segunda classe (a de atalhos de repositorios) … métodos como… addAll(EntityCollectionManager manager) … containsAll(EntityCollectionManager manager) … removeAll(EntityCollectionManager manager) …

Esta classe repositorios teria que ver a lista de de coleções do manager… para cada coleção, invocar o método correspondente, e passar a coleção como parametro…

o problema todo está nas tipologias…

se eu tiver

repAlunos = DataBase.getCurrentEntityRepository(Aluno.class); //o comando add do repositorio só irá aceitar alunos repAlunos.addAll(Collection<Aluno> entitys);

o problema está aqui… quando eu faço…

listaDeClasses = manager.getEntityClasses(); //eu recebo 1 Iterator com a lista de classes que tem dentro do manager... while(listaDeClasses.hasnext()) { entityClass = listaDeClasses.next(); manager.getEntityCollection(entityClass); //isto vai me retornar a coleção para primeira classe de entidades //eu sei que tanto "entityClass" como "manager.getEntityCollection(entityClass)" são referentes a alunos, e são da mesma classe //porem meu compilador não aceita fazer contaisAll(entityClass, manager.getEntityCollection(entityClass)); //a tipologia dois para o compilador é <? extends IEntitySignature> e ele não entende que os 2 são da mesma classe //apesar de que "entityClass" é uma Class<Aluno> e manager.getEntityCollection(entityClass) é uma Collection<Aluno> //o fato é que como manager.getEntityClasses(); me reporta uma lista sem a tipologia definida, eu precisaria fazer um cast... //mas eu não sei fazer um cast do tipo (Class<entityClass.getClass()>)entityClass ... entendeu o problema ??

Deixa eu ver se eu entendi… sua situação atual é a seguinte, certo?

import java.util.Collection;
import java.util.Iterator;

public class TesteTipo {

	private interface IEntidade {};
	
	private class Repositorio {
	
		public <E extends IEntidade> boolean contaisAll(Class<E> entityClass,
			 	Collection<E> entitys) {
			return false;
		}
	}
	
	private class Manager {

		 public <T extends IEntidade> Collection<T> getEntityCollection 
			(Class<T> forThisClass) {  
			 return null; 
		 }
		 
		 public Iterator<Class<? extends IEntidade>> getEntityClasses() {
			 return null;
		 }
		 
		 public void addEntity(IEntidade entity) { }
	 }
	 
	 public static void main(String[] args) {
		TesteTipo t = new TesteTipo();
		Repositorio repositorio = t.new Repositorio();
		Manager manager = t.new Manager();
		Iterator<Class<? extends IEntidade>> listaDeClasses = manager.getEntityClasses();
		while(listaDeClasses.hasNext()) {
			Class<? extends IEntidade> clazz = listaDeClasses.next();
			boolean b = repositorio.contaisAll(clazz, manager.getEntityCollection(clazz)); // essa linha dá erro
		}
	}
}

Acho que a maneira mais fácil de resolver o problema é evitar que o compilador faça a verificação de tipos…:

import java.util.Collection;
import java.util.Iterator;

public class TesteTipo {

	private interface IEntidade {};
	
	private class Repositorio {
	
		public <E extends IEntidade> boolean contaisAll(Class<E> entityClass,
			 	Collection<E> entitys) {
			return false;
		}
	}
	
	private class Manager {

		 public <T extends IEntidade> Collection<T> getEntityCollection 
			(Class<T> forThisClass) {  
			 return null; 
		 }
		 
		 public Iterator<Class> getEntityClasses() {
			 return null;
		 }
		 
		 public void addEntity(IEntidade entity) { }
	 }
	 
	 public static void main(String[] args) {
		TesteTipo t = new TesteTipo();
		Repositorio repositorio = t.new Repositorio();
		Manager manager = t.new Manager();
		Iterator<Class> listaDeClasses = manager.getEntityClasses();
		while(listaDeClasses.hasNext()) {
			Class clazz = listaDeClasses.next();
			boolean b = repositorio.contaisAll(clazz, manager.getEntityCollection(clazz));
		}
	}
}

É feio? É… mas resolve :stuck_out_tongue:

é MarceloS… é +ou- isso dai mesmo…

só que remover o tipo gera um outro problema…

Eu tenho 1 classe assim… Repository<E extends IEntidade> …

quando alguem faz… containsAll(Collection<Aluno> collection) por exemplo…
esse contains all… chama o repositorio Repository<Aluno> para resolver o assunto…

e o repositorio que entende de Alunos é o Repository<Aluno> … c eu mandar 1 coleção de Matriculas pra ele, vai dar merda ^^

enfim… se eu num tiver a confirmação de tipologia, não consigo invocar o repositorio correto pra tratar… lembrando que além de containsAll() tempos addAll, etc etc etc … é preciso saber o tipo, pro tratamento ser de acordo la do lado da persistencia… não sei pq não funciona

Olha… não sei como vc implementou o método pra chamar o repositório, mas em tempo de execução, a classe que você terá chamando como “Class” é a mesma que você terá chamando como “Class<? extends AlgumaCoisa>”… tirando os <> você só evita que o compilador verifique isso pra você.

me tira uma dúvida… c eu tenho um método assim…

Repositories.class[code]public <E extends IEntitySignature> void updateAll(Collection<E> entitys) {
//Aqui dentro eu tenho como saber a classe E ?? o simples seria E.class …

   //O ideal era fazer assim
   DataBase.getCurrentEntityRepository(E.class).updateAll(entitys);

}
}[/code]preciso buscar o repositorio do tipo E … do mesmo tipo da coleção… só que não sei fazer isso … fiz uma gambiarra ali…

Repositories.class@SuppressWarnings("unchecked") public &lt;E extends IEntitySignature&gt; void updateAll(Collection&lt;E&gt; entitys){ if (entitys.size() &gt; 0) { E firstElement = entitys.iterator().next(); Class&lt;E&gt; entitysClass = (Class&lt;E&gt;)firstElement.getClass(); DataBase.getCurrentEntityRepository(entitysClass).updateAll(entitys); } }

E apenas a titulo de informação…
DataBase.classpublic static &lt;E extends IEntitySignature&gt; Repository&lt;E&gt; getCurrentEntityRepository(Class&lt;E&gt; entityClass)
Repository<T>.classpublic abstract class Repository&lt;T extends IEntitySignature&gt; { //... public final TransactionResult addOrUpdateAll(Collection&lt;T&gt; entitys) //...
A ressalva é… Repository<T> tem que ter tipologia… seu modo de criar é … new Repository<T>(Class<T> classe) … e eu preciso disso por questões de persistencia…

Repositories.class

//public &lt;E extends IEntitySignature&gt; void updateAll(Collection&lt;E&gt; entitys) {
public void updateAll(Collection entitys) {
     Class clazz = entitys.get(0).getClass();
     DataBase.getCurrentEntityRepository(clazz).updateAll(entitys);
}
// ou ainda
public void updateAll(Collection entitys, Class clazz) {
       DataBase.getCurrentEntityRepository(clazz).updateAll(entitys);
}
public void updateAll(Collection entitys){
	if (entitys.size() &gt; 0) {
		Object firstElement = entitys.iterator().next();
		Class entitysClass = firstElement.getClass();
		DataBase.getCurrentEntityRepository(entitysClass).updateAll(entitys);
	}
}

Acredito que você não tenha maiores problemas tirando o tipo daquele método; você só vai ter um monte de "warnings" gerados pelo compilador avisando que você está fazendo operações "unchecked"…

O problema é que a classe Repositories é publica… é usada por outras pessoas, e algum ignorante (quando falo ignorante, falo desinformado) pode tentar enviar uma Collection de Objejetos que não assinam IEntity… isso vai gerar uma exceção em tempo de execução… ai depois o bug vai ter q ser rastreado, ate verificar que algum burrinho, fez a cagada de não checar o tipo… preferia não liberar o tipos incopativeis com o repositório… ai se alguem kizer mandar um tipo genérico mesmo assim, ai já não posso fazer nada ^^, pelomenos o aviso vai ta la no método ao olho de todos