Métodos usando generics

Eaê, galera!

Criei um método que extrai dados de uma tabela de strings e gera uma lista de objetos, usando reflexão. O problema é que, até o momento, meu método retorna uma lista de Object, queria saber se é possível que ele retorne uma lista do tipo passado como parâmetro diretamente. Segue meu código abaixo.

Obrigado pela ajuda!

protected List<Object> getObjectsFromTable(
		List<List<String>> table,
		Class<?> type,
		String[] fields_names,
		Class<?>[] fields_types)
			throws Throwable {
	/* Pega os setters do objeto. */
	Method[] methods = new Method[fields_names.length];
	for (int i = 0; i < fields_names.length; i++) {
		String field_name = fields_names[i];
		String method_name = "set" + Character.toUpperCase(field_name.charAt(0)) +
				field_name.substring(1);
		
		methods[i] = type.getMethod(method_name, new Class<?>[]{fields_types[i]});
	}
	
	List<Object> result = new ArrayList<Object>();
	
	/* Percorre as linhas da tabela. */
	ListIterator<List<String>> i = table.listIterator();
	while (i.hasNext()) {
		/* Nova instância do objeto. */
		Object aux = type.newInstance();
		
		/* Pega os campos da linha atual. */
		List<String> campos = i.next();
		ListIterator<String> j = campos.listIterator();
		for (int index = 0; index < fields_names.length; index++) {
			String campo = j.next().toUpperCase();
			Class<?> tipo = fields_types[index];
			if (tipo == String.class) {
				methods[index].invoke(aux, campo);
			} else if (tipo == long.class) {
				methods[index].invoke(aux, Long.parseLong(campo));
			} else if (tipo == int.class) {
				methods[index].invoke(aux, Integer.parseInt(campo));
			} else {
				throw new IllegalArgumentException("Invalid type!");
			}
		}
		
		result.add(aux);
	}
	
	return result;
}

[quote=pdform]Eaê, galera!

Criei um método que extrai dados de uma tabela de strings e gera uma lista de objetos, usando reflexão. O problema é que, até o momento, meu método retorna uma lista de Object, queria saber se é possível que ele retorne uma lista do tipo passado como parâmetro diretamente. Segue meu código abaixo.

Obrigado pela ajuda!

[/quote]

retorne uma lista do tipo passado como parâmetro diretamente “isso me parace meio redundante”.

:arrow: http://www.artima.com/lejava/articles/neal_gafter_closures.html , estou lendo esse artigo aqui e me pareceu algo interessante ao que vc , perguntou …

Exatamente… na verdade, eu formulei mal a pergunta: eu queria passar o tipo uma única vez como parâmetro generics e já retornar a lista desse tipo. O melhor que consegui até agora foi isso:

protected static <T> List<T> getObjectsFromTable(
		List<List<String>> table,
		Class<? extends T> type,
		String[] fields_names,
		Class<?>[] fields_types)
			throws Throwable {
	/* Pega os setters do objeto. */
	Method[] methods = new Method[fields_names.length];
	for (int i = 0; i < fields_names.length; i++) {
		String field_name = fields_names[i];
		String method_name = "set" + Character.toUpperCase(field_name.charAt(0)) +
				field_name.substring(1);
		
		methods[i] = type.getMethod(method_name, new Class<?>[]{fields_types[i]});
	}
	
	List<T> result = new ArrayList<T>();
	
	/* Percorre as linhas da tabela. */
	ListIterator<List<String>> i = table.listIterator();
	while (i.hasNext()) {
		/* Nova instância do objeto. */
		T aux = type.newInstance();
		
		/* Pega os campos da linha atual. */
		List<String> campos = i.next();
		ListIterator<String> j = campos.listIterator();
		for (int index = 0; index < fields_names.length; index++) {
			String campo = j.next().toUpperCase();
			Class<?> tipo = fields_types[index];
			if (tipo == String.class) {
				methods[index].invoke(aux, campo);
			} else if (tipo == long.class) {
				methods[index].invoke(aux, Long.parseLong(campo));
			} else if (tipo == int.class) {
				methods[index].invoke(aux, Integer.parseInt(campo));
			} else {
				throw new IllegalArgumentException("Invalid type!");
			}
		}
		
		result.add(aux);
	}
	
	return result;
}

O problema é que eu precisso passar e type, para poder usar reflection dentro do método, o que é redundante. Como eu poderia pegar T.class?

Obrigado pela ajuda!

infelizmente nao da. eu escrevi um artigo exatamente sobre isso:

http://blog.caelum.com.br/2008/04/28/nao-posso-descobrir-nem-instanciar-tipos-genericos-porque/

é uma limitacao do java.

Sim, tem que ser redundante. Um é para o compilador saber o tipo e o outro é para que a sua lógica saiba o tipo. O compilador não é capaz de ver a sua lógica, e o type-erasure impede que a sua lógica veja o generic do compilador. Por isso tem que ser redundante.

Quiçá o java 7 resolve esse problema com reification. ERASE THE ERASURE!

Sim, tem que ser redundante. Um é para o compilador saber o tipo e o outro é para que a sua lógica saiba o tipo. O compilador não é capaz de ver a sua lógica, e o type-erasure impede que a sua lógica veja o generic do compilador. Por isso tem que ser redundante.

Quiçá o java 7 resolve esse problema com reification. ERASE THE ERASURE![/quote]

:arrow: Contraditório então pela a afirmação do Paulo Silveira, citado acima ???

Sim, tem que ser redundante. Um é para o compilador saber o tipo e o outro é para que a sua lógica saiba o tipo. O compilador não é capaz de ver a sua lógica, e o type-erasure impede que a sua lógica veja o generic do compilador. Por isso tem que ser redundante.

Quiçá o java 7 resolve esse problema com reification. ERASE THE ERASURE![/quote]

:arrow: Contraditório então pela a afirmação do Paulo Silveira, citado acima ???[/quote]

Não, não é contraditório.

Ele tem que passar e type, algo que é redundante porque o é para o compilador entender e type é para a lógica do programa entender.

Não dá, no java 6, para fazer sem ser redundante. Você não pode instanciar um generic ou descobri-los por reflection porque eles são perdidos na compilação. Não estão lá nos bytecodes. A “gambiarra” para colocá-los nos bytecodes é colocar o type, um Class explícito com o qual você pode trabalhar na lógica do seu programa. O problema é que isso duplica o tipo, uma vez que e type são na verdade a mesma coisa. E como não é possível fazer o compilador entender o type, apenas o , você é obrigado a colocar os dois.

Mas, no java 7, está planejado a reificação dos generics, que basicamente faz com que o exista nos bytecodes e que por isso possa ser visto no reflection. Isso elimina a necessidade de existir o type e elimina a necessidade de haver redundância.

[quote=victorwss]…Sim…(…)…
…(…)…
…Mas, no java 7, está planejado a reificação dos generics, que basicamente faz com que o exista nos bytecodes e que por isso possa ser visto no reflection. Isso elimina a necessidade de existir o type e elimina a necessidade de haver redundância…[/quote]

:thumbup: Bom, eu não sei porque uma afirmação e depois algo que vem a ser de uso favorável em sua colocação, entretando acho que o Paulo Silveira poderia melhor informar no seu blog, pois simplesmente ele direciona para uma pagina http://gafter.blogspot.com/2006/11/reified-generics-for-java.html , que depois contradiz tudo sobre o que, vem a ser uma coisa para Java 5 e outra evolução no Java 7.

bem Marcio, nao consegui entender direito o que voce escreveu. Acho que voce nao percebeu que eu e o Victor estamos falando a MESMA coisa: eu no blog e ele naquela frase. O movimento erase the erasure teria de criar um SEGUNDO tipo de generics, ja que o generics da maneira atual que foi implementada, atraves de erasures, NAO DA para pegar o tipo generico em tempo de execucao.

Pra eles colocarem a reificacao, tera de criar esse segundo tipo de generics (sugerido como em vez de ) . Esse sim seria atraves de reificacao, que nao existe hoje.

Repetindo a minha afirmacao mais claramente: hoje em dia, com o generics como esta, nao da para fazer isso. E nem vai dar sem criar um OUTRO generics. Eles nao vao fazer o mesmo pois seria uma quebra de compatibilidade (nao da pra por reificacao em cima de erasure sem quebra de compatibilidade, nao vao fazer isso, como ja afirmaram).

[quote=victorwss]
Mas, no java 7, está planejado a reificação dos generics, que basicamente faz com que o exista nos bytecodes e que por isso possa ser visto no reflection. Isso elimina a necessidade de existir o type e elimina a necessidade de haver redundância.[/quote]

Isso, mas nao sera a mesma sintaxe.

E infelizmente nao esta planejado, estao pensando mas muita gente fala que nao vai ter.

[quote=Paulo Silveira]
bem Marcio, (…)
(…)… tipo generico em tempo de execucao.

Pra eles colocarem a reificacao, tera de criar esse segundo tipo de generics (sugerido como em vez de ) . Esse sim seria atraves de reificacao, que nao existe hoje.

Repetindo a minha afirmacao mais claramente: hoje em dia, com o generics como esta, nao da para fazer isso. E nem vai dar sem criar um OUTRO generics. Eles nao vao fazer o mesmo pois seria uma quebra de compatibilidade (nao da pra por reificacao em cima de erasure sem quebra de compatibilidade, nao vao fazer isso, como ja afirmaram).[/quote]

:thumbup: Ficou mais esclarecido, porque estava acreditando que a reificação já era algo aprimorado sobre que fora colocado ao Java 7, mas já que ainda não existe,a informação do victor virou tese.

Valeu !!!

Não é redundante. É assim mesmo que se faz. T não é passado para lado nenhum ele é apenas um marcador (não um objecto). Vc pode deixar assim.

protected static <T> List<T> getObjectsFromTable(
		List<List<String>> table,
		Class<T> type,
		String[] fields_names,
		Class<?>[] fields_types)
	
}

:arrow: Informação pode ser vista melhor no Blog da Caelum.

:idea: http://blog.caelum.com.br/2008/04/28/nao-posso-des...anciar-tipos-genericos-porque/

:thumbup: