Converter um Object para uma classe

Olá galera, to com um probleminha aqui e gostaria q vcs me ajudassem, sou novo na área de programação POO e to com umas dificuldades com reflexão. Tipo tenho o seguinte método:

public Collection<Object> select(Object o, String campo, String busca, String ordem, String direcao){
		if(o == null){
			throw new NullPointerException("Não foi encontrado um objeto para a inserção");
		}
		
		if(!o.getClass().isAnnotationPresent(Tabela.class)){
			throw new RuntimeException("Objeto não pode ser persistido,\nnão existe a anotação para a tabela");
		}
		
		Class cls = o.getClass();
		StringBuilder Sql = new StringBuilder("SELECT ");
		Field[] fields = cls.getDeclaredFields();
		int x = 1;
		int chave = 0;
		for(Field field : fields){
			Annotation anot = field.getAnnotation(Coluna.class);
			Annotation anotChave = field.getAnnotation(ChavePrimaria.class);
			if(anotChave instanceof ChavePrimaria){
				chave += 1;
			}
			if(chave > 1){
				throw new RuntimeException("Não pode conter 2 chaves primarias");
			}
			if(anot instanceof Coluna){
				Sql.append(field.getName()+(x==fields.length?" FROM ":", "));
			}
			x++;
		}
		
		for(Annotation anot : cls.getAnnotations()){
			if(anot instanceof Tabela){
				Tabela tabela = (Tabela)anot;
				Sql.append(tabela.nome()+" WHERE ");
			}
		}
		
		if(campo!=null && busca!=null){
			Sql.append(campo+" like '"+busca+"%'");
		}
		
		if(ordem!=null && direcao!=null){
			Sql.append(" ORDER BY "+ ordem +" "+direcao );
		}
		
		Statement stm = null;
		ResultSet rs = null;
		Collection<Object> retorno = null;
		try {
			stm = this.conn.createStatement();
			rs = stm.executeQuery(Sql.toString());
			while(rs.next()){
				retorno.add(rs.getInt("codigo"));
				retorno.add(rs.getString("nome"));
				retorno.add(rs.getString("telefone"));
				retorno.add(rs.getString("dataNascimento"));
			}
			stm.close();
			
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return retorno;
	}

esse metodo me etorna uma Collection de objetos, correto. Só que eu preciso converter essa colection na regra de negócio em uma coleção de objetos do tipo da classe q eu criei como pessoa, para que eu possa passa-la para minha página jsp.
O meu método que não estou conseguindo concluir e esse:

public Collection<Pessoa> doSelect(String campo, String busca , String ordem, String direcao){
		DefaultDAO dao = new DefaultDAO();
		Collection<Object> arr = dao.select(new Pessoa(), campo, busca, ordem, direcao);
		
		/* O meu problema se encontra aqui 
                 * em como converter essa Collection<Object>
                 * em uma Collection<Pessoa> para que eu possa fazer um
                 * laço em minha página jsp
                 */

		return null;
	}

Se alguem puder me ajudar já agradeço, Obrigado galera
Valewwwwwwwwwwwwwww!!!

A assinatura de seu método não está legal. Você deveria fazer, em vez disto:

public Collection<Object> select(Object o, String campo, String busca, String ordem, String direcao)

isto aqui:

public <T> Collection<T> select (Class<T> klass, String campo, String busca, String ordem, String direcao)

Para a chamada, teríamos algo como:

Collection<Pessoa> arr = dao.select(Pessoa.class, campo, busca, ordem, direcao);

OK? (Acho que os detalhes sórdidos de o que deve ser alterado no seu método “select” devem ser óbvios para você.)

Opa valew irmão, kra to fazendo aqui mas me deparei com um problema, como ainda to tentando entender o q vc me aconselhou encontrei esse problemas olha:

public <T> Collection<T> select(Class<T> classe, String campo, String busca, String ordem, String direcao){
		if(classe == null){
			throw new NullPointerException("Não foi encontrado um objeto para a inserção");
		}
		
		if(!classe.isAnnotationPresent(Tabela.class)){
			throw new RuntimeException("Objeto não pode ser persistido,\nnão existe a anotação para a tabela");
		}
		
		Class cls = classe;
		StringBuilder Sql = new StringBuilder("SELECT ");
		Field[] fields = cls.getDeclaredFields();
		int x = 1;
		int chave = 0;
		for(Field field : fields){
			Annotation anot = field.getAnnotation(Coluna.class);
			Annotation anotChave = field.getAnnotation(ChavePrimaria.class);
			if(anotChave instanceof ChavePrimaria){
				chave += 1;
			}
			if(chave > 1){
				throw new RuntimeException("Não pode conter 2 chaves primarias");
			}
			if(anot instanceof Coluna){
				Sql.append(field.getName()+(x==fields.length?" FROM ":", "));
			}
			x++;
		}
		
		for(Annotation anot : cls.getAnnotations()){
			if(anot instanceof Tabela){
				Tabela tabela = (Tabela)anot;
				Sql.append(tabela.nome()+" WHERE ");
			}
		}
		
		if(campo!=null && busca!=null){
			Sql.append(campo+" like '"+busca+"%'");
		}
		
		if(ordem!=null && direcao!=null){
			Sql.append(" ORDER BY "+ ordem +" "+direcao );
		}
		
		Statement stm = null;
		ResultSet rs = null;
		Collection<T> retorno = null;
		
		try {
			stm = this.conn.createStatement();
			rs = stm.executeQuery(Sql.toString());
			while(rs.next()){
				[i]retorno.add(rs.getInt("codigo"));
				retorno.add(rs.getString("nome"));
				retorno.add(rs.getString("telefone"));
				retorno.add(rs.getString("dataNascimento"));[/i]
                                /* aqui ta dando problema comos tipos
                                 * The method add(T) in the type Collection<T> is                    
                                 *not applicable for the arguments (int)
                                 */
			}
			stm.close();
			
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return retorno;
	}
Collection<T> retorno = null;

Amigo, você tem dois problemas aqui.

a) Você não instanciou nenhum ArrayList<T> ou coisa parecida (vai dar uma null pointer exception com certeza!)

b) Como é que você está fazendo um método genérico, se você tem este código aqui:

 			while(rs.next()){
 				retorno.add(rs.getInt("codigo"));
 				retorno.add(rs.getString("nome"));
 				retorno.add(rs.getString("telefone"));
 				retorno.add(rs.getString("dataNascimento"));
 			}

Provavelmente você iria querer algo como:

while (rs.next) {
    T t = klass.newInstance();
    ... preencher os campos de t com os dados que você leu do resultset;
    retorno.add (t);
}

Isso esbarramos em outro ponto que eu não estava conseguindo fazer:
Tenho este codigo q vc me mostrou:

 while (rs.next) {
     T t = klass.newInstance();
     ... só que aqui como to pegando generio nao sei como  prencher os
 campo de t, uma vez que vc instancia ele via Klass.newInstace().
     retorno.add (t);
 }

Como faço isso, Ah e não entendia a parte do ArrayList que vc falow

a) Em vez de

Collection<T> retorno = null;

faça:

Collection<T> retorno = new ArrayList<T>();

b) Perguntinha. Esse método é só para retornar Collection<Pessoa> ou ele pode retornar outros tipos de objetos (por exemplo, Collection<Loja>)? Senão não precisa ser genérico, como eu achei inicialmente que deveria ser.

hehehe, na minha ignorancia queria cria um metodo que pudesse retornar uma Collection ou uma Collection…etc, mas não tenho tal conhecimento necessário, estou aprendendo agora

Se você quer fazer um método que retorna uma Collection<Pessoa>, Collection<Loja> etc, você tem de remover esses comandos:

				retorno.add(rs.getInt("codigo"));
 				retorno.add(rs.getString("nome"));
 				retorno.add(rs.getString("telefone"));
 				retorno.add(rs.getString("dataNascimento"));

do seu método. É que uma loja não tem data de nascimento, e acho que não tem sexo também…

Uma forma é delegar isso para sua classe. Você pode fazer o seguinte:

  1. A classe “Pessoa”, “Loja” etc. implementam uma interface que tem um método que, dado um recordset, preenche os campos.

  2. Você pode escrever uma classe que pega um objeto Pessoa, Loja etc., pega os nomes dos campos, o recordset, e tenta preencher os campos de acordo com os campos das tabelas. Isso pode ser feito via configuração ou annotations, como você já estava fazendo.

Olha meu codigo no momento está assim:

	public <T> Collection<T> select(Class<T> classe, String campo, String busca, String ordem, String direcao){
		if(classe == null){
			throw new NullPointerException("Não foi encontrado um objeto para a inserção");
		}
		
		if(!classe.isAnnotationPresent(Tabela.class)){
			throw new RuntimeException("Objeto não pode ser persistido,\nnão existe a anotação para a tabela");
		}
		
		Class cls = classe;
		StringBuilder Sql = new StringBuilder("SELECT ");
		Field[] fields = cls.getDeclaredFields();
		int x = 1;
		int chave = 0;
		for(Field field : fields){
			Annotation anot = field.getAnnotation(Coluna.class);
			Annotation anotChave = field.getAnnotation(ChavePrimaria.class);
			if(anotChave instanceof ChavePrimaria){
				chave += 1;
			}
			if(chave > 1){
				throw new RuntimeException("Não pode conter 2 chaves primarias");
			}
			if(anot instanceof Coluna){
				Sql.append(field.getName()+(x==fields.length?" FROM ":", "));
			}
			x++;
		}
		
		for(Annotation anot : cls.getAnnotations()){
			if(anot instanceof Tabela){
				Tabela tabela = (Tabela)anot;
				Sql.append(tabela.nome()+" WHERE ");
			}
		}
		
		if(campo!=null && busca!=null){
			Sql.append(campo+" like '"+busca+"%'");
		}
		
		if(ordem!=null && direcao!=null){
			Sql.append(" ORDER BY "+ ordem +" "+direcao );
		}
		
		Statement stm = null;
		ResultSet rs = null;
		Collection<T> retorno = new ArrayList<T>();
		
		try {
			stm = this.conn.createStatement();
			rs = stm.executeQuery(Sql.toString());
			while(rs.next()){
				try {
					T t = classe.newInstance();
					for(Field field : fields){
						Annotation anot = field.getAnnotation(Coluna.class);
						if(anot instanceof Coluna){
							retorno.add();
                                                        Meu problema é que não sei como          pegar o valor aqui.
                                                        Como poderia ser feita essa parte, considerando as anotações que eu já
                                                        tenho, para que idempendente do tipo do campo eu
                                                        possa adicionar em meu retorno???
						}
					}
					
				} catch (InstantiationException e) {
					e.printStackTrace();
				} catch (IllegalAccessException e) {
					e.printStackTrace();
				}
			}
			stm.close();
			
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return retorno;
	}

Isso eu não faço nem ideia de como pode ser feito…

T t = klass.newInstance();
((MinhaInterfaceMagica) t).preencheUsandoOMeuRecordset (rs);
retorno.add (t);

e

class Pessoa implements MinhaInterfaceMagica {
...
    public void preencheUsandoOMeuRecordset (ResultSet rs) {
        this.nome = rs.getString ("nome");
        bla bla bla
    }
}
T t = klass.newInstance();
MinhaClasseMagicaQuePegaUmObjeto.ePreencheUsandoOMeuRecordset (t, rs);
retorno.add (t);

Outra coisa que percebi no seu código é que você não entendeu para que serve uma collection. É para adicionar uma Pessoa, ou Loja, não para adicionar um campo de uma Pessoa, ou Loja, de cada vez.

add (new Pessoa());

não

add (“nome da pessoa”); add (“idade da pessoa”); … etc.

valew de mais pela aula
mas tenho muito q aprender ainda, vou continuar tentando aqui

Essa parte da reflaction eu entendi, o q eu naum entendi e q eu tenho uma classe que foi passada pra ela e criou uma instancia, como que eu vou Acessar para essa instancia independende de qual classe que ela é Pessoa ou Loja os metodos de acesso get e set para que eu possa atribuir valores para minha instancia antes de adciona-la a collection

Suponha que sua classe seja assim:

class Pessoa {
    private String nome;

    public String getNome () { return nome; }
    @Campo ("nome") public void setNome (String nome) {
        this.nome = nome;
    }
}

(eu pus uma Annotation porque você conhece, mas não é preciso usar Annotations se você configurar de outra maneira, ou se sempre os campos do banco de dados forem correspondentes aos campos da classe.

Se você tiver um objeto do tipo Pessoa, você pode obter sua classe (Pessoa.class), e dela listar os métodos cujo nome começa por “set” (como setNome, setTelefone etc), ver se eles são void ou outra coisa, e ver se eles têm apenas 1 parâmetro. Então, em resumo:

  • Se achar o método set____, então veja se ele tem uma Annotation “@Campo”. Se existir, então o nome do campo do banco de dados você já achou.
  • Se esse método set____ existir, então veja quais os parâmetros que ele recebe. Se for apenas 1, então de acordo com o tipo do parâmetro (String, int etc.) você pode chamar o método de Resultset adequado (getString, getInt etc.)
  • Se pegar o valor correto, então é só invocar o método.

Você teria um exemplo desse codigo? É que já tentei tanto q to ate me confundindo de como posso fazer…

Você estava “quase” no caminho certo, mas estava procurando pelos campos do objeto. É melhor usar só os setters e getters, porque você pode ter problemas de acessar campos privados.

kra eu naum faço ideiia de como eu pego um metodo por reflecção to tendando aqui mas naum sai nada

Parei aqui, aqui parece que travei…

public <T> Collection<T> select(Class<T> classe, String campo, String busca, String ordem, String direcao){
		if(classe == null){
			throw new NullPointerException("Não foi encontrado um objeto para a inserção");
		}
		
		if(!classe.isAnnotationPresent(Tabela.class)){
			throw new RuntimeException("Objeto não pode ser persistido,\nnão existe a anotação para a tabela");
		}
		
		Class cls = classe;
		StringBuilder Sql = new StringBuilder("SELECT ");
		Field[] fields = cls.getDeclaredFields();
		int x = 1;
		int chave = 0;
		for(Field field : fields){
			Annotation anot = field.getAnnotation(Coluna.class);
			Annotation anotChave = field.getAnnotation(ChavePrimaria.class);
			if(anotChave instanceof ChavePrimaria){
				chave += 1;
			}
			if(chave > 1){
				throw new RuntimeException("Não pode conter 2 chaves primarias");
			}
			if(anot instanceof Coluna){
				Sql.append(field.getName()+(x==fields.length?" FROM ":", "));
			}
			x++;
		}
		
		for(Annotation anot : cls.getAnnotations()){
			if(anot instanceof Tabela){
				Tabela tabela = (Tabela)anot;
				Sql.append(tabela.nome()+" WHERE ");
			}
		}
		
		if(campo!=null && busca!=null){
			Sql.append(campo+" like '"+busca+"%'");
		}
		
		if(ordem!=null && direcao!=null){
			Sql.append(" ORDER BY "+ ordem +" "+direcao );
		}
		
		Statement stm = null;
		ResultSet rs = null;
		Collection<T> retorno = new ArrayList<T>();
		
		try {
			stm = this.conn.createStatement();
			rs = stm.executeQuery(Sql.toString());
			while(rs.next()){
				
				Method[] metodos = classe.getClass().getMethods();
				T objeto = null;
				for(int i=0;i < metodos.length; i++){
					Method m = metodos[i];
					Aqui eu não to conseguindo fazer mais nada
				}
				retorno.add(objeto);
				
				
			}
			stm.close();
			
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return retorno;
	}

Se você usar mais que 5 níveis de chaves “{}” você trava mesmo. Separe o que você quer fazer em um método separado, e veja bem o que está fazendo. Não se esqueça de seguir o que recomendei.