Ajuda com método genérico e elegante

7 respostas
Fox_McCloud

Estou construindo um projetinho pessoal aqui, e eu fiz uma classe com constantes, que está funcionando corretamente (abaixo)...

package model;

import java.awt.Color;
import java.io.IOException;
import java.util.Properties;

enum Type {
	STRING,
	INT,
	HEXA
}

public class Constants {

	private static final Properties CONFIG_PROPERTIES = loadConfig("/model/config/config.properties");
	
	public static final String WINDOW_TITLE = (String)loadProperty("window.title", Type.STRING);
	public static final int WINDOW_WIDTH = (Integer)loadProperty("window.width", Type.INT);
	public static final int WINDOW_HEIGHT = (Integer)loadProperty("window.height", Type.INT);
	public static final int NUM_BUFFERS = (Integer)loadProperty("num.buffers", Type.INT);
	public static final int FPS = (Integer)loadProperty("fps", Type.INT);
	public static final Color BORDER_COLOR = new Color((Integer)loadProperty("border.color", Type.HEXA));
	public static final Color BACKGROUND_COLOR = new Color((Integer)loadProperty("background.color", Type.HEXA));

	private static Properties loadConfig(String configFileName) {
		Properties props = new Properties();
		try {
			props.load(Object.class.getResourceAsStream(configFileName));
		} catch (IOException e) {
			e.printStackTrace();
			System.exit(0);
		}
		return props;
	}

	private static Object loadProperty(String key, Type type) {
		String value = CONFIG_PROPERTIES.getProperty(key);
		Object property = null;
		try{
			switch(type){
				case STRING:
					property = value;
					break;
				case INT:
					property = Integer.parseInt(value);
					break;
				case HEXA:
					property = Integer.parseInt(value, 16);
					break;
			}
		} catch(Exception e) {
			System.err.println("Erro ao carregar a propriedade "+key);
			e.printStackTrace();
			System.exit(0);
		}
		return property;
	}
	
}
O que me deixa desconfortável é essa "gambi" na função loadProperty(), onde eu tenho que informar o tipo de dado que eu quero para realizar a operação necessária sobre o String de valor, e depois realizar um casting sobre o Object retornado.

Assim, quem pode me ajudar a construir um método generic que consiga retornar o tipo de dado correto e saber qual operação realizar internamente sobre o String de valor? Ah, sem utilizar aquele enum e, sendo possível, utilizando um código mais elegante...

Uma assinatura assim, eu imaginei...

private static <T> T loadProperty(String key) {
	/** código **/
}
Já verifiquei em um teste que o método consegue substituir o <T> na compilação de acordo com o tipo da variável que recebe o resultado do método... Ex:
public static final int WINDOW_WIDTH = loadProperty("window.width");
Em tempo de compilação o <T> será substituído por Integer, já que o tipo da variável WINDOW_WIDTH é int. Só que dentro do método eu não consigo fazer um teste do tipo T instanceof Integer, nem chamar algo específico como T.parseInt(value)... realmente não faz sentido...

Então como eu posso fazer? Alguém aí que manda bem em Generics pode me ajudar?

:wink:

7 Respostas

B

Ola

Vc até consegue fazer isto usando o generics, mas teria que passar o tipo de dado que vc quer receber… tipo, a ssinatura teria que mudar para:

private static <T> T loadProperty(T a, String key)

O List faz isto no metodo )]toArray

tnaires

Realmente, não dá pra saber o tipo do parâmetro em tempo de execução. O que pode ser feito é adicionar um parâmetro ao método do tipo Class<T>, e ao chamar o método, passar o tipo da classe.

Ficaria assim:

private static &lt;T&gt; T loadProperty(String key, Class&lt;T&gt; type) { /** código **/ }
E, ao chamar o método:

loadProperty("window.width", Integer.class);

Abraços

victorwss

A reification do java 7 visa resolver esse problema. Enquanto ela não chega, passar o parâmetro do tipo Class<T> é a melhor solução.

Fox_McCloud

tnaires:
Realmente, não dá pra saber o tipo do parâmetro em tempo de execução. O que pode ser feito é adicionar um parâmetro ao método do tipo Class<T>, e ao chamar o método, passar o tipo da classe.

Ficaria assim:

private static &lt;T&gt; T loadProperty(String key, Class&lt;T&gt; type) { /** código **/ }
E, ao chamar o método:

loadProperty("window.width", Integer.class);

Abraços


Interessante, gostei…

Eu nem sabia que isso era um problema!

:stuck_out_tongue:

LottaLava

[size=18][color=olive]Opá, grave suas propriedades já informando o tipo de cada variável no arquivo de configuração, assim você sempre irá saber o que esta lendo.
:mrgreen:
[/color][/size]

Fox_McCloud

LottaLava:
[size=18][color=olive]Opá, grave suas propriedades já informando o tipo de cada variável no arquivo de configuração, assim você sempre irá saber o que esta lendo.
:mrgreen:
[/color][/size]

É até interessante fazer assim, eu já havia até pensado nisso…

Mas tudo que abre margem pro usuário fazer Hgada tira a robustez da aplicação, que precisa ser resistente a Hgadas…

Além disso eu gostaria de ver uma implementação utilizando Generics… mas o pessoal aqui já deu boas idéias…

Fox_McCloud

Só pra constar, segue em anexo um jar auto-executável do “pograminha”, é uma animaçãozinha simples para estudar detecção de colisões…

Requer Java 5.

Contém fontes!

Criado 11 de julho de 2008
Ultima resposta 11 de jul. de 2008
Respostas 7
Participantes 5