Instanciar classe dinamicamente[RESOLVIDO]

11 respostas
L

Olá…

Tenho um método que utiliza um xstream para ler um arquivo com registros xml parecido com isso…claro…retirei um monte de linhas que não importam agora:

public List lerXML(String textoXML,Class classe){
           xstream = new XStream(new DomDriver());
            xstream.alias("mapping", Vector.class);
            xstream.alias(classe.getSimpleName(), classe);

          List lstRegistros = (List) xstream.fromXML(textoXML);
          return lstRegistros;
}

Esse método, resumidamente, le o texto xml extraído de um arquivo e transforma num list de objetos para mim poder armazenar no bd do sistema
Meu problema é que cheguei num ponto do sistema em que tenho que fazer uma rotina que le vários arquivos, e não sem como fazer para reconhecer se o arquivo é de produto, por exemplo, de cliente para gerar um class para passar como argumento para o método.

Assim… tenho uma pasta chamada recepcao, onde lá conterá vários arquivos, cada arquivo possui o nome da tabela do bd que devo inserir os dados de dentro dele…
ex: produto.xml é para inserir os dados na tabela do bd de produto, assim por diante…

como eu faço para gerar um Produto.class para passar como argumento para meu método lerXML sem fazer um punhado de ifs para cada tabela do bd?

pois recebo vários arquivos…ex: cliente.xml produto.xml, pedido.xml itempedido.xml…etc…

prescisaria de algo que pegasse o nome do arquivo e conseguisse instanciar o bean dele… pois os beans são os mesmos nomes dos arquivos também…

11 Respostas

R

Pra ter a classe a partir de uma String é bem simples na verdade.Class classe = Class.forName("Produto");Se o arquivo tem o mesmo nome que a classe, é só remover a extensão e pronto.

Mas lembre-se, você pode ter que especificar o pacote também.

L

Hum…vou testar aqui e já retorno o resultado…

B

Cara de bate pronto não vejo uma forma mais simples que implementar alguns if’s para direcionar que classe instanciar. Talvez de pra fazer algo genérico, pegando o nome do arquivo, dando um substring na primeira letra depois um toUpperCase(), a claro, pegando no substring tudo que vem antes de .xml. Ai fica a seu criterio.

[]'s

B

Acho que a sugestão do Rodrigo seria o que você precisa, certo?

Testa ai e fala pra gente se funcionou.

[]'s

L

Obrigado pelas sugestões…deu certinho com esse esquema do rodrigo sasaki

e antes de chegar nesse ponto, formatei a string com as dicas do bastides, tirando o “.xml” e transformando a primeira em maiúscula…

Class classe = Class.forName("Produto");

80% dos beans ele reconhece na primeira… agora outro problema me surgiu…creio que vou ter que modificar alguma coisa na hora de formar os arquivos, pois
existem beans com nomes duplos, por ex: RecebimentoParcial, ItemPedido, etc… no qual tem duas letras maiúsculas daí não tenho como adivinhar no meio da palavra como fazer um toUpperCase()…

S

leopoldof:
Obrigado pelas sugestões…deu certinho com esse esquema do rodrigo sasaki

e antes de chegar nesse ponto, formatei a string com as dicas do bastides, tirando o “.xml” e transformando a primeira em maiúscula…

Class classe = Class.forName("Produto");

80% dos beans ele reconhece na primeira… agora outro problema me surgiu…creio que vou ter que modificar alguma coisa na hora de formar os arquivos, pois
existem beans com nomes duplos, por ex: RecebimentoParcial, ItemPedido, etc… no qual tem duas letras maiúsculas daí não tenho como adivinhar no meio da palavra como fazer um toUpperCase()…

O que vc está aprendendo na prática é que usar Class.forName não é uma boa solução. Parece, mas não é.
O ue acontece quando o nome do arquivo não coincidir com nenhuma classe ? Hoje isso não acontece, mas poderá eventualmente acontecer.

Use um Map<String, Class> que vc popula com os nomes dos arquivos e as classes correspondentes. Mas melhor que isso é usar uma outro objeto no meio, um FileReader . Este objeto recebe o File do arquivo e sabe como ler. Se for simplesmente usando a classe, ok, mas se for mais complexo que isso este design tb salva vc. Em suma, vc precisa de um nível de indireção adicional que abstrair como ler o arquivo dado o File que o representa.

R

sergiotaborda:
O que vc está aprendendo na prática é que usar Class.forName não é uma boa solução. Parece, mas não é.
O ue acontece quando o nome do arquivo não coincidir com nenhuma classe ? Hoje isso não acontece, mas poderá eventualmente acontecer.

Use um Map<String, Class> que vc popula com os nomes dos arquivos e as classes correspondentes. Mas melhor que isso é usar uma outro objeto no meio, um FileReader . Este objeto recebe o File do arquivo e sabe como ler. Se for simplesmente usando a classe, ok, mas se for mais complexo que isso este design tb salva vc. Em suma, vc precisa de um nível de inderação adicional que abstrair como ler o arquivo dado o File que o representa.


Eu pensei em sugerir isso também, mas o que me veio a mente é que a cada arquivo novo, o Map terá que ser alterado também.

Mas o que eu achei que era complexidade, vi agora que é segurança :slight_smile:

B

Caso continue usando o class.forName(), pode alterar o modo de criar o arquivo…tipo:

Item_produto, assim voce consegue identificar onde termina um palavra e começa a outra.

Eu não entendi direito como seria usar o Map<String, Class> que o sergiotaborda sugeriu.

[]'s

R
bastides:
Caso continue usando o class.forName(), pode alterar o modo de criar o arquivo..tipo:

Item_produto, assim voce consegue identificar onde termina um palavra e começa a outra.

Eu não entendi direito como seria usar o Map que o sergiotaborda sugeriu.

[]'s
Fica algo mais ou menos assim:
public class Teste{
	
	private Map<String, Class<?>> map;
	
	public Teste(){
		map = new HashMap<String, Class<?>>();
		map.put("produto", Produto.class);
		map.put("pedido", Pedido.class);
		map.put("itempedido", ItemPedido.class);
		map.put("recebimentoparcial", RecebimentoParcial.class);
	}

	public Class<?> buscarClasse(String str){
		return map.get(str);
	}
	
}
L

Usando o map até poderia dar certo…só que eu teria que lembrar…daqui dois anos…se caso criasse uma tabela a mais na base de dados e alterasse o programa …e ir nessa parte do código e adicionar um item a mais no map…

A questão de modificar o nome dos beans fica complicado, pois são uns 30 beans… e aqui foi adotado sempre a mesma metodologia para o sistema inteiro em relação a nomes de classes, além dos nomes dos beans, teria que mudar todos os xmls de mapeamento do hibernate… e por aí vai… iria virar uma folia…

Mas o que eu tinha que revisar e centrar a atenção também para resolver este problema é na hora de gerar o arquivo também e não somente na hora de ler, pois no outro módulo onde o arquivo é gerado, eu utilizo os beans para gerar o xml… então…assim como a idéia passada do

classe = Class.forName(nome);

onde nome seria o nome do arquivo, (sem a extensão),

utilizei o mesmo princípio para gerar o nome dele no outro módulo assim

String nomeArquivo = lstRegistro.get(0).getClass().getCanonicalName();

Pronto…resolvido a questão… assim fica a geração de uma forma dinâmica… e a leitura dos arquivos também…caso daqui um ano seja acrescentado mais uma tabela na base de dados, e mapeada no hibernate, o módulo de envio gerará corretamente o arquivo…e o módulo de leitura lerá corretamente o arquivo recebido…

Obrigado aos mestres do java pelas sugestões, foram de grande valia…

E fica aqui a experiência…se algum dia alguém tiver um problema parecido…está aqui uma forma de resolver…

S

leopoldof:
Usando o map até poderia dar certo…só que eu teria que lembrar…daqui dois anos…se caso criasse uma tabela a mais na base de dados e alterasse o programa …e ir nessa parte do código e adicionar um item a mais no map…

Não teria que lembrar. Basta codificar uma exception se o nome não for encontrado. E não é se criar mais uma tabela, é se criar mais um arquivo.
Se vc tiver um ProdutosNovos.xml e ProdutosForaDeLinha.xml o classforname não funciona mais.

Por isso que eu falei para vc criar um FileReader. E crie um FileWriter também se precisar. E coloque isso no map, e coloque tudo isso no spring. Pronto.
Usar “class” diretamente é pedir para ter problemas. Depois vc pode fazer um FileReader muto simples baseado na classe, mas isso é uma opção , o fileReader pode ser usar outro mecanismos.
Não amarre o seu mecanismo de entrada/saída porque ele tente da evoluir bastante.

Criado 20 de fevereiro de 2013
Ultima resposta 22 de fev. de 2013
Respostas 11
Participantes 4