Acesso simples e rápido às linhas de uma query

Abaixo segue duas classes para encapsular e facilitar o acesso a banco de dados via JDBC, a classe DBQuery encapsula uma query onde a mesma é capaz de gerar um iterator para navegação nas linhas da consulta de forma rápida, leve e eficiente.

O iterator é implementado de uma forma em que ele não guarde os dados da consulta em memória, possibilitando o uso dessa classe para queries que retornem muitas linhas de resultado.

Outra coisa interessante é a possibilidade de se trabalhar com genéricos, caso sua consulta ao banco retorne um tipo homogêneo de dados (por exemplo, todos os campos sejam do tipo String).

classe DBQuery.java

/**
 *
 * @author Paulo Canedo C Rodrigues
 */
public class DBQuery<t> implements Iterable</t><t> {
 
    private Connection connection;
    private String query;
 
    public DBQuery(Connection connection, String query) {
        this.connection = connection;
        this.query = query;
    }
 
    public Iterator</t><t> iterator() {
        try {
            Statement stm = connection.createStatement();
            ResultSet rs = stm.executeQuery(query);
            return new DBRowIterator(rs);
        } catch (SQLException ex) {
            return null;
        }
    }
}</t>

classe DBRowIterator.java

/**
 *
 * @author Paulo Canedo C Rodrigues
 */
public class DBRowIterator<t> implements Iterator<map <String, T>> {
 
    private ResultSet rs;
    private Map<string , T> rowFields = new HashMap</string><string , T>() {
 
        //Sobrescrita do metodo get do mapa para transformar o get em case insensitive
        @Override
        public T get(Object key) {
            return super.get(((String) key).toUpperCase());
        }
    };
    private String[] columnsName;
    private boolean objectReaded = false;
    private int columnCount;
 
    DBRowIterator(ResultSet rs) throws SQLException {
        this.rs = rs;
 
        columnCount = rs.getMetaData().getColumnCount();
        columnsName = new String[columnCount];
 
        for (int i = 0; i < columnCount; i++) {
            columnsName[i] = rs.getMetaData().getColumnName(i + 1).toUpperCase();
        }
    }
 
    public boolean hasNext() {
        if (objectReaded == false && rowFields.size() != 0) {
            return true;
        }
 
        try {
            boolean flag = rs.next();
            if (flag = true) {
                rowFields.clear();
                for (int i = 0; i < columnCount; i++) {
                    Object o = rs.getObject(i + 1);
                    rowFields.put(columnsName[i], (T) o);
                }
            } else {
                if (rowFields != null) {
                    try {
                        rs.getStatement().close();
                        rs.close();
                    } catch (Exception ex) {
                    }
                }
                rowFields = null;
            }
            return flag;
        } catch (Exception ex) {
        }
        return false;
    }
 
    public Map<String, T> next() {
        objectReaded = true;
        return rowFields;
    }
 
    public void remove() {
    }
}
</string></map></t>

Abaixo segue dois exemplos de utilização, por favor, deixem comentário sobre o que achou das classes e da ideia.

java.sql.Connection connection = null;
 
//Exemplo 1 com genérico sem casting - apenas para tipo de dados homogêneos
DBQuery dbQuery1 = new DBQuery(connection, "SELECT nome, sobrenome, endereco FROM tb_agenda ORDER BY nome");
for (Iterator<map <String, String>> it = dbQuery1.iterator(); it.hasNext();) {
    Map<string , String> linhaDaConsulta = it.next();
    String nome = linhaDaConsulta.get("nome"); //nome do campo da consulta: case insensitive
    String sobrenome = linhaDaConsulta.get("sobrenome");
    String endereco = linhaDaConsulta.get("endereco");
    System.out.println(String.format("Nome: %s; Sobrenome: %s; Endereço: %s", nome, sobrenome, endereco));
}
 
//Exemplo 2 sem genérico com casting
DBQuery dbQuery2 = new DBQuery(connection, "SELECT nome, idade, peso FROM tb_pessoa ORDER BY nome");
for (Iterator<map <String, Object>> it = dbQuery2.iterator(); it.hasNext();) {
    Map<string , Object> linhaDaConsulta = it.next();
    String nome = (String) linhaDaConsulta.get("nome");
    Integer idade = (Integer) linhaDaConsulta.get("idade");
    Float peso = (Float) linhaDaConsulta.get("peso");
    System.out.println(String.format("Nome: %s; Idade: %d; Peso: %.2f", nome, idade, peso));
}</string></map></string></map>

Swing Hacks – Um botão diferente e elegante

Imagem do Botão elegante

Imagem do Botão elegante

Atualmente estou estudando bastante diferentes formas de melhorar o visual e comportamento do swing, então comecei criando o botão personalizado. O botão ficou até bonitinho :) O que eu acho bem interessante é que tomei bastante cuidado em manter a compatibilidade com o modo design dos IDEs, testei com o matisse do NetBeans e funcionou perfeitamente em modo design, os três principais campos são o text, icon e o description, sendo que este último é o único campo não herdado do JButton, todos eles podem ser modificados, por exemplo, pela janela propriedades do NetBeans.

Estou pensando em implementar um novo lookandfeel, mas por enquanto esse botão foi feito sobrescrevendo alguns métodos paint do JButton, entretanto não acho que seja possível fazer esse componente através de um UI do lookandfeel.

Propriedades do botão no NetBeans

Propriedades do botão no NetBeans

Utilize e modifique livremente o código fonte, mas por favor mantenha os créditos no source.

Clique aqui para baixar o source com o binário.