Problemas com HashTable e ArrayList

9 respostas
D

Olá,

Tenho um problema, eu estou usando um ArrayList e adiciono a ele uma classe que contém um atributo do tipo Hashtable, acontece que quando adiciono um novo elemento ao ArrayList todos os elementos da lista ficam iguais aos que adicionei, segue classes e retorno:

public class retCampos   
{  
  
   private String NomeCampo;  
   private String TipoCampo;  
   private String Valor;  
        
        .... getters e setters...  
}

Classe Dinâmica:

public class DynamicClass   
{  
     
   public Hashtable<Integer,retCampos> campos  = new  Hashtable<Integer, retCampos>();  
  
}

Como estou acessando:

s = db.createStatement();  
         rs = s.executeQuery(sql);  
           
         rsMetaData = rs.getMetaData ();  
           
           
     
         for (int i = 1; i <= rsMetaData.getColumnCount (); i++)   
         {  
            t = new retCampos();  
            //System.out.println (rsMetaData.getColumnName (i) +  
                //       " of type " +  
                //       rsMetaData.getColumnTypeName (i));  
   
            t.setNomeCampo(rsMetaData.getColumnName(i));  
            t.setTipoCampo(rsMetaData.getColumnTypeName(i));  
            //System.out.println("Inserindo Campo: " + t.getNomeCampo() + " Tipo: " + t.getTipoCampo());  
            todosCampos.add(t);  
            //unSQL.campos.put(i, t);  
         }  
           
           
         while (rs.next ())   
         {  
              unSQL = new DynamicClass();   
               
                
              for (int i=0; i < todosCampos.size(); i++)  
              {  
                  t = new retCampos();  
                  t = todosCampos.get(i);  
                    
                  indiceColuna = rs.findColumn(t.getNomeCampo());  
                    
                  if (t.getTipoCampo().equalsIgnoreCase("INTEGER"))  
                  {  
                     t.setValor(Integer.toString((rs.getInt(indiceColuna))));   
                  } else if (t.getTipoCampo().equalsIgnoreCase("VARCHAR"))  
                  {  
                    t.setValor(rs.getString(indiceColuna));  
                  }  
                    
                                      
                                      
                  unSQL.campos.put(i, t);  
                    
                    
              }  
              //System.out.println("Usuario db: " + rs.getString(1) + " Nome db: " + rs.getString(2) +  " email db: " + rs.getString(3));  
                 
              retSQL.add(unSQL);  
              imprimeSQL(unSQL);  
              imprimeSQL(retSQL);  
                
                 
                
                   
         }

Quando dou um print na tela segue o resultado:

UNSQL ------------------------------- UNSQL

Campo: CUSUARIO Tipo:INTEGER Valor:61
Campo: NOME Tipo:VARCHAR Valor:maria
Campo: EMAIL Tipo:VARCHAR Valor:maju@

UNSQL ------------------------------- UNSQL

RETSQL ------------------------------- RETSQL

Campo: CUSUARIO Tipo:INTEGER Valor:61
Campo: NOME Tipo:VARCHAR Valor:maria
Campo: EMAIL Tipo:VARCHAR Valor:maju@

RETSQL ------------------------------- RETSQL

UNSQL ------------------------------- UNSQL

Campo: CUSUARIO Tipo:INTEGER Valor:46
Campo: NOME Tipo:VARCHAR Valor:roberto.rabello
Campo: EMAIL Tipo:VARCHAR Valor:roberto.@

UNSQL ------------------------------- UNSQL

RETSQL ------------------------------- RETSQL

Campo: CUSUARIO Tipo:INTEGER Valor:46
Campo: NOME Tipo:VARCHAR Valor:roberto.rabello
Campo: EMAIL Tipo:VARCHAR Valor:roberto@
Campo: CUSUARIO Tipo:INTEGER Valor:46
Campo: NOME Tipo:VARCHAR Valor:roberto.rabello
Campo: EMAIL Tipo:VARCHAR Valor:roberto@

RETSQL ------------------------------- RETSQL

Já pesquisei um monte e procurei no google o dia todo e até agora não tive retorno, alguém pode me dar uma luz ?

9 Respostas

ViniGodoy

O Hashtable, assim como o Vector, não deve ser mais utilizado. No lugar, use um HashMap.

D

Olá Viny, obrigado pela resposta.

Substitui por HashMap e continua o mesmo problema.

Atenciosamente,

Darlan Carrião
[telefone removido]

ViniGodoy

Acho que o problema está na sua lógica.

Na linha 30, você cria um objeto do tipo retCampos.

Esse objeto é descartado na linha 31, quando vc substitui o valor da variável t, pelo objeto da lista criada na iteração anterior. Você então altera os dados desse objeto para definir os valores baseado no registro em questão.

No próximo passo do while, você irá fazer a mesma coisa, para o mesmo objeto (aquele obtido a partir da lista), com os dados do próximo registro.

Repense sua lógica. Há algo errado aí. Use o debugger para executar o código passo-a-passo e ver certinho o que está acontecendo em cada iteração. E pense como você gostaria que esse resultado retornasse corretamente para o usuário.

D

Olá Vinny, mais uma vez obrigado pela dica :smiley:

Então, vamos lá, o que eu preciso fazer: criar uma classe dinâmica, que independente da query que fizer vai servir mais ou menos como um VO. O problema não está na lógica, comentei a linha 30 e então recompilei e continuou dando o mesmo problema…

fiz um debug dos valores e eles aparecem no unSQL da linha 51 perfeitamente, com todos os campos preenchidos, com os valores corretos, tanto que até fiz a impressão do mesmo, acontece que quando dou um add no ListArray todas as linhas do Array são substituidas pelo novo valor adicionado…

Atenciosamente,

Darlan Carrião

ViniGodoy

E onde vc dá esse add?

D

Olá Vinny,

Faço isto na linha 51, dentro do while do retorno da base de dados.

Atenciosamente,

Darlan Carrião

D

Ah, detalhe, segue como a lista retSQL está definida (onde os dados estão ficando bagunçados):

ArrayList<DynamicClass> retSQL = new ArrayList<DynamicClass>();
ViniGodoy

Estranho, pq um ArrayList é um vetorzão. Então não faz nem sentido os dados ficarem bagunçados. O comportamento que você descreveu ocorre quando normalmente alguém coloca várias referências ao mesmo objeto dentro do ArrayList. Ou quando se usa um HashSet sem o método hashCode e equals implementados corretamente.

Só uma dica. Defina sempre as collections por sua interface (List, Set, ou Map):

List<DynamicClass>  retSQL = new ArrayList<DynamicClass>();  
Map<Integer,retCampos> campos  = new  HashMap<Integer, retCampos>();

O tipo específico de lista deve só aparecer depois do “new”. Para parâmetros de métodos, tipos de propriedades e valores de retorno, prefira sempre a interface.

Isso facilitará caso você precise trocar de implementação de lista no futuro (para um LinkedList, por exemplo).

Você pode listar aí o método imprimeSql?

D

Vinny, obrigado pela resposta.

Já tentei mudar a lista várias vezes, nenhuma funcionou, valeu pela dica, aí segue o método imprimeSQL:

public static void imprimeSQL(ArrayList <DynamicClass> retSQL)
    {
    	DynamicClass imprimesql;
    	retCampos cmp;
    	
    	System.out.println("");
    	System.out.println("RETSQL ------------------------------- RETSQL");
    	System.out.println("");
	

                for (int i=0; i<retSQL.size(); i++)
	{
		retorno = retorno + "/>\n          <" + tabela; 
		imprimesql = new DynamicClass();
		imprimesql = retSQL.get(i);
	
	
	
		for (int j=0; j < imprimesql.campos.size();j++)
		{
				
		    cmp = new retCampos();
		    cmp = (retCampos)imprimesql.campos.get(j);
	  	    System.out.println("Campo: " + cmp.getNomeCampo() + " Tipo:" + cmp.getTipoCampo() + " Valor:" + cmp.getValor());
		}
	
	}
	System.out.println("");
	System.out.println("RETSQL ------------------------------- RETSQL");	
	System.out.println("");
			
    }

obs: quando eu faço um debug os valores de retSQL já estão repetidos lá no método imprimeSQL;

Atenciosamente,

Darlan Carrião

Criado 18 de março de 2010
Ultima resposta 18 de mar. de 2010
Respostas 9
Participantes 2