Generics e reflection

5 respostas
carlos.e.a

Olá pessoal,

Bom, estou usando uma API(acho que pela descrição do problema alguns saberão qual é) que por algum motivo que desconheço quando vou criar um Dao o generico é da seguinte forma:

Dao<T,ID>

Onde T seria o tipo da entidade e ID o tipo do id da classe. Só que esse ID ao meu ver é totalmente desnecessário ja que posso descobrir por reflection. Então criei um metodo que fazia essa descoberta. Só que me deparei com o problema:

Como passo o tipo descoberto para o Dao<T,ID>. Meu metodo retorna um Class<?> e se chama getIdType(T classe) onde classe é a entidade. Quando tento fazer Dao<T, getIdType(classe)> não funciona. O que afinal devo passar quando estou instanciando um tipo generico? Isso abalou meus conhecimentos de generics :roll:

Fiz umas buscas mas nao encontrei nada, principalmente pela dificuldade de formular uma busca para tal.

5 Respostas

gomesrod

Isso não funciona porque os Generics são aplicados em tempo de compilação do programa e não de execução. Essa maneira de fazer exigiria a execução do método getIdType() para obter o tipo, o que não faz nenhum sentido para o compilador.

carlos.e.a

Certo,

Alguma sugestao de como resolver isso? xD

Pq fica mt tosco passar como parametro pro meu metodo uma coisa que eu posso descobrir e livrar quem está chamando disso.

gomesrod

Você pode parametrizar a classe apenas pelo tipo da entidade (T) , e os métodos que precisam do ID seriam especialmente parametrizados com o tipo do ID.
Na maioria das situações essa solução vai se comportar exatamente como você quer, porque ele é capaz de deduzir o tipo do ID de acordo com o que foi passado no parâmetro.

Um exemplo básico, apenas com create() e find()

public class GenericDaoTest {

	public static void main(String[] args) {
		// Cria o DAO, parametrizado apenas pelo tipo da ENTIDADE, sem usar o tipo do ID
		GenericDao<Entidade> dao = new GenericDao<Entidade>(Entidade.class);
		
		// Sem novidades no create, ele não usa o ID de qualquer maneira
		Entidade e1 = new Entidade();
		dao.create(e1);

		Integer idToSearch = 10;

		// Chamando método genérico, passando o parâmetro do tipo do ID
		Entidade e2 = dao.<Integer>find(idToSearch);
		
		// Na verdade não precisa do tipo, ele é capaz de deduzir pelo
		// que foi passado no parâmetro!
		// No final o tipo do ID fica transparente.
		Entidade e3 = dao.find(idToSearch);
	}
}

class Entidade {
	Integer id;
	String outroCampo;
}

class GenericDao<T> {
	Class<T> entityClass;
	EntityManager em; // Poderia tambem ser a sessao do hibernate
	
	public GenericDao(Class<T> entityClass) {
		this.entityClass = entityClass;
	}

	// Metodo que nao precisa do ID. Ok, funciona normalmente
	void create(T entity) {
		em.persist(entity);
	}
	
	// Metodo que precisa do ID é genérico, 
	// parametrizado pelo tipo do ID
	<ID_TYPE> T find(ID_TYPE id) {
		return em.find(entityClass, id);
	}
}
wagnerfrancisco

gomesrod:
Você pode parametrizar a classe apenas pelo tipo da entidade (T) , e os métodos que precisam do ID seriam especialmente parametrizados com o tipo do ID.
Na maioria das situações essa solução vai se comportar exatamente como você quer, porque ele é capaz de deduzir o tipo do ID de acordo com o que foi passado no parâmetro.

Mas nesse caso qualquer tipo que eu passe por parâmetro vai ser considerado como o tipo do id, certo? A checagem do tipo do id meio que se perde. Se você passar o tipo errado, só vai descobrir em tempo de execução.

Eu ainda prefiro passar o T e o ID pro Dao, se as minhas entidades tiverem ids de tipos diferentes…

gomesrod

É verdade! Pensei na praticidade mas acaba perdendo em segurança.

Criado 18 de fevereiro de 2013
Ultima resposta 19 de fev. de 2013
Respostas 5
Participantes 3