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!!!
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;
}
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
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
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:
A classe “Pessoa”, “Loja” etc. implementam uma interface que tem um método que, dado um recordset, preenche os campos.
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.
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.
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
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ê 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.
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.