Mirror DSL: facilitando o uso da API de reflection

Por Jonas Abreu em 17/11/08

No último domingo foi feito o primeiro release público do projeto Mirror (versão 1.2).

O Mirror é um projeto que tem por objetivo facilitar o uso da Java Reflection API, removendo boa parte da burocracia (como as diversas checked exceptions que são lançadas) e utilizando uma DSL para melhorar a legibilidade do código.

Com essa remoção de burocracia e a DSL, é possível transformar o seguinte código:

Field toSet = null;
for (Field f : target.getClass().getDeclaredFields()) {
    if (f.getName().equals("field")) {
        toSet = f;
    }
}
if (toSet != null && ((toSet.getModifiers() & Modifier.STATIC== 0)
        && ((toSet.getModifiers() & Modifier.FINAL== 0)) {
    toSet.setAccessible(true);
    toSet.set(target, value);
}

em algo mais legível e expressivo:

Mirror.on(target).set().field("fieldName").withValue(value);

Atualmente o Mirror possui suporte para lidar com as operações reflectivas mais comuns (como instanciar objetos, invocar métodos, ler ou escrever atributos, etc). Ele foi desenvolvido por Adriano Almeida, Diego Feitosa e eu, todos consultores/instrutores aqui da Caelum, enquanto enfretavamos problemas comuns no dia a dia.

Esperamos que possa ser útil para vocês também!

Java Annotations: directing, enabling?

Por Fabio Kung em 22/09/08

Há algum tempo, quando trabalhava na Alemanha, costumava ter diversas conversas e discussões extremamente produtivas com um grande amigo e desenvolvedor, Tiago Silveira. Como não poderia deixar de ser, desenvolvimento de software era o preferido entre diversos assuntos interessantes.

Em uma de nossas conversas, falávamos sobre o uso de anotações em Java. A discussão foi tão produtiva, que chegamos a concordar que o uso de anotações pode ser encarado como atitude com relação ao desenvolvimento de software!

Foi o próprio Tiago que começou a falar sobre enabling vs directing e começamos a fazer algumas comparações com o uso de anotações em projetos famosos.

Anotações são apenas metadados (ou DecorativeData, como alguns podem preferir); informações extras sobre o código que está escrito. Eu costumo sempre fazer analogia com um post-it pendurado no meio do seu código fonte: anotações não executam código.

Na minha opinião, o bom uso de anotações segue o estilo “Enabling”. Não te direcionam para nenhum caminho, não indicam a execução de nenhum código. Pelo contrário, como metadados, apenas possibilitam diversos usos desta informação extra. Um bom exemplo seria a anotação @Entity, da Java Persistence API:

@Entity
public class Carro {
  // …
}

Diversos frameworks e até outras partes do seu sistema podem usar esta informação extra como bem entenderem. O próprio hibernate usa esta informação para saber que se trata de uma classe persistente, que deve ter representação no banco relacional, um validador poderia usar esta informação para decidir que objetos desta classe devem ser validados, um framework de aspectos poderia decidir aplicar um aspecto nesta classe baseado nesta informação extra, entre diversas outras possibilidades. Um outro exemplo interessante poderia ser a anotação @Transient, da própria especificação JPA:

public class Bicicleta {
  @Transient
  private double velocity;
}

Você poderia usar esta informação para decidir não mostrar este campo na interface gráfica (web ou desktop). Pode usar esta informação extra até para decidir que este campo não será enviado em emails, nem incluso em logs. Frameworks de ORM como o hibernate aproveitam esta informação para ignorar o atributo e não incluí-lo em nenhuma tarefa de persistência.

Poderia dar mais inúmeros exemplos de bons usos de anotações. O mais importante é a idéia de que a anotação possibilita diversos usos e não direciona - não força - nenhum caminho. A anotação não está associada a nenhuma execução de código. Funciona mesmo como um simples post-it.

A atitude alternativa seria o pensamento “Directing”. Neste caso, a anotação está diretamente relacionada a execução de algum código e serve apenas para este fim. Exemplo:

public class Sistema {

  @EnviaEmail(Emails.CONFIRMACAO)
  public void cadastra(Usuario usuario) {
    //…
  }

}

Neste caso não há outro uso para esta anotação. Perceba que ela já pressupõe a execução do código de envio de emails. Te limita a um pensamento particular, para um uso específico. Talvez seja um caso exagerado, mas não há diferença alguma com a chamada direta do método que envia o email:

public class Sistema {
 
  public void cadastra(Usuario usuario) {
    mensageiro.enviaEmail(Emails.CONFIRMACAO, usuario);
    // …
  }
 
}

Em alguns casos pode ser bastante difícil, ou até subjetivo demais, decidir se o uso de uma anotação é directing ou enabling. Não acho que devemos tomar nada como verdade absoluta; o importante é ter consciência dos diversos pontos de vista diferentes. Assim podemos tomar as nossas decisões, sempre pesando vantagens e desvantagens.

E você, consegue lembrar de algum outro uso interessante de anotações? Enabling ou Directing?

Caelum Stella - o cinto de utilidades para o desenvolvedor brasileiro

Por Fabio Kung em 21/05/08

stellaDurante o Falando em Java 2008 do último fim de semana (18/05/2008), anunciamos o lançamento do novo Caelum Stella.

O projeto vem para auxiliar os desenvolvedores brasileiros, suprindo algumas das necessidades comumente encontradas em aplicações desenvolvidas aqui no Brasil. Atualmente, o Caelum Stella fornece uma biblioteca de validadores, formatadores e conversores para documentos brasileiros, tais como CPF, CNPJ e PIS/PASEP.

 String cpf = "867.554.707-24";
 CPFValidator vld = new CPFValidator();
 for(ValidationMessage error : vld.invalidMessagesFor(cpf)) {
   System.out.println(error.getMessage());
 }

Há uma alternativa que lança uma exceção caso ocorra algum problema de validação:

 new CPFValidator().assertValid("867.554.707-24");

O Stella também inclui módulos extras, como o de geração de boletos bancários, adaptadores para JSF, VRaptor, JBoss Seam e Hibernate Validator. Veja um exemplo de validação para CPFs usando o Caelum Stella junto ao Hibernate Validator:

  @Entity
  public class Modelo {
    @CPF
    private String cpf;
  
    public String getCpf() {
      return cpf;
    }
  }

O módulo Stella Faces conta com alguns validadores compatíveis com a especificação JSF, que você pode adicionar aos seus componentes:


<h:inputText id="cpf" value="#{usuarioBean.cpf}">
  <stella:validateCPF/>
</h:inputText>

O Stella Boleto procura fornecer um idioma mais fluente para a geração de boletos, através do encadeamento de métodos, gerando PDFs, PNGs e em breve TXT, RTF e HTML:

  Boleto boleto = Boleto.newBoleto()
      .withBanco(banco).withDatas(datas)
      .withDescricoes("descricao 1""descricao 2""descricao 3")
      .withEmissor(emissor).withSacado(sacado)
      .withValorBoleto("200.00").withNoDocumento("1234")
      .withInstrucoes("instrucao 1""instrucao 2""instrucao 3")
      .withLocaisDePagamento("local 1""local 2");

  new BoletoGenerator(boleto).toPNG("teste.png");

Estão ainda previstas no roadmap do projeto funcionalidades como JSP taglibs, rotinas JavaScript para máscaras, validação e suporte a formulários, seleção de cidades dependente da seleção de estados, suporte a mais documentos, geração da nota fiscal eletrônica, webservices para busca de endereços através de CEP, entre muitas outras. A lista vem sendo constantemente atualizada e você pode conferi-la através deste link.

Todas estas funcionalidades estão divididas em diversos módulos dentro do Stella. Atualmente são quatro: Stella Core, Stella Hibernate, Stella Faces e Stella Boleto. Cada um com um propósito diferente, mas todos relacionados aos problemas do dia a dia recorrentes no mercado brasileiro.

Além de facilitar a vida dos desenvolvedores brasileiros, o projeto prima pela alta qualidade (extensa quantidade de testes unitários, cobertura e documentação) e facilidade de uso. Você pode conferir diversas características técnicas do projeto e dos vários módulos na página técnica, gerada pelo maven. Lá você encontra a lista de responsáveis (e respectivos emails), a ótima cobertura dos testes para cada um dos módulos e o código fonte navegável para cada um dos módulos.

Como de costume em qualquer projeto open-source, o código fonte está disponível em um repositório SVN (subversion) no sourceforge.net. Para baixar os fontes basta usar seu cliente preferido:

svn checkout http://caelum-stella.svn.sourceforge.net/svnroot/caelum-stella/trunk

Você também pode navegar pelo repositório neste link.

Para tirar as suas dúvidas, sugerir funcionalidades, apontar bugs e discutir sobre o projeto, não deixe de assinar as listas de discussão, que podem ser encontradas aqui. Se preferir, pode postar também no GUJ.

Visite, use, comente e participe do desenvolvimento do projeto!

stella.caelum.com.br

Não posso descobrir nem instanciar tipos genéricos! Porque?

Por Paulo Silveira em 28/04/08

São incontáveis os posts no GUJ com uma pergunta semelhante: “Posso extrair o nome de um tipo genérico?“, “Não consigo extrair tipo do genérico!“, “Utilizando generics para instanciar objetos“, entre outros. Curioso que esse tipo de pergunta tem aumentado muito nos últimos tempos, identificando um possível crescimento no uso do Java 5 em diante. Já era a hora!

Eu já havia postado sobre isso quando falei de reificação de tipos parametrizados, mas de uma maneira mais geral.

A questão básica é a seguinte: Se eu tenho um tipo genérico, que recebe um tipo parametrizado T como argumento, eu posso instanciar T de alguma forma?

Quem sabe tentar assim:

class Dao<T> {
  public T cria() {
    return new T();
  }  
}

Essa forma não funciona. Você não tem garantias sobre os construtores que o tipo T possui. E então se tentarmos assim:

class Dao<T> {
  public T cria() {
    return T.class.newInstance();
  }  
}

Aqui a sintaxe até poderia ser possível, mas infelizmente o java não sabe quem é T nem mesmo em tempo de execução. Nem mesmo com manipulação de bytecode ou qualquer outro recurso. Isso porque o compilador “apaga” essa informação depois de utilizada: é a tal da mal falada erasure.

Qual seria a vantagem da erasure?

Antes de mais nada: erasure não serve para poder rodar código do Java 5 em VMs Java 1.4 ou menor! Não é esse o objetivo.

Quando a JSR14 do generics foi proposta, eles queriam mais que compatibilidade para trás em relação a compilação, eles queriam também a possibilidade de migrar o código antigo para poder usar código novo: uma ArrayList precisa poder ser passada como argumento para alguém que receba List<QualquerClasse> como argumento!

Para ilustrar a situação, imagine que eu tenho uma aplicação grande X que usasse a classe ArrayList em muitos lugares (como a grande maioria das aplicações). Essa aplicação X usa a biblioteca B, que recebe List como argumento em muitos de seus métodos. Se um dia a bibioteca B passasse a usar List genérica, gostaríamos que a aplicação X atualizasse B sem maiores problemas: sem precisar recompilar nada, nem trocar nada no código fonte. O Neal Gafter escreveu muito sobre isso pouco antes da release do Java 5, dada as inúmeras críticas que eles estavam recebendo.

Se o Java tivesse optado por outra maneira de implementar generics, teria ou quebrado compatibilidade com o uso não genérico de classes que viraram genéricas, ou precisaria criar classes paralelas as atuais, praticamente copiadas e coladas, só que estas genéricas, tornando as antigas deprecated ou legadas.

Como o .NET resolveu o mesmo problema?

O .NET seguiu essa segunda forma, e criou uma hierarquia quase que paralela de coleções dentro do name space System.Collections.Generic.

A IList é a interface que define as operações em uma lista não genérica, e a ArrayList é sua implementação mais comumente usada. Quando entrou generics no .NET eles criaram uma outra interface para a lista, com mesmo nome, só que genérica: a IList<T>.

A classe List já é a implementação da interface genérica, e é ela quem você vai usar em vez de ArrayList. Ela possui uma definição bem estranha:

public class List : IList, ICollection,
    IEnumerable, IList, ICollection, IEnumerable

Ela implementa tanto a lista genérica como a não genérica. O .NET tem um recurso que nós não temos, que faz com que apesar dessa lista também implementar a interface não genérica, você só consegue invocar os métodos não genéricos (que trabalham com Object) se estiver se referenciando a ela explicitamente como uma lista não genérica, como o código abaixo:

IList x = new List<String>();
x.Add(2);

Apesar desse código compilar, no .NET temos essa informação dos tipos genéricos em tempo de execução, o que fará gerar uma exceção:

System.ArgumentException: The value "2" is not of type "System.String" e cannot be used in this generic collection

No Java teríamos apenas um unchecked warning na linha da declaração da referência, e uma possível ClassCastException mais a frente no código.

Aqui a vantagem é você poder passar uma List genérica para um código .NET antigo, que recebe como argumento uma IList não genérica. Além disso, no .NET você pode sim descobrir quem é T em tempo de execução:

class ClasseGenerica<T> {
  void metodo() {  Console.WriteLine(typeof(T))}
}

Em resumo: o sistema de generics do .NET é realmente seguro, não temos como burlá-lo através de unchecked casts, como ocorre em Java. O Java novamente sacrificou alguns recursos interessantes em favor a compatibilidade de versões e interoperabilidade entre classes genéricas e as não genéricas já existentes. Cada um com sua vantagem. Como citei no outro artigo, existem algumas idéias de dar suporte a tipos genéricos reificados no Java, ao mesmo tempo que outros ficariam ainda com a erasure, sendo que você pode escolher qual o que te agrada para aquela classe genérica em particular. Talvez ter as duas opções adicione ainda mais complexidade a tipagem genérica do Java, mas eu particularmente gosto da idéia.

Mais uma vez um post que era para ser sucinto ficou longo. Agradeço ao Rafael Steil e Rodrigo Kumpera pela colaboração, e ao Lucas Cavalcanti e Guilherme Moreira pedindo para que fosse elaborado um post mais completo sobre esse assunto tão pertinente.

Nova apostila: Algoritmos e Estruturas de Dados com Java

Por Rafael Cosentino em 20/02/08

A Caelum está lançando hoje mais uma apostila disponível gratuitamente para download: Algoritmos e Estruturas de Dados em Java.

Ela vem sendo formulada há algum tempo, baseada na experiência do curso de versão do IME USP “Algoritmos e Estruturas de dados” que é ministrado por Paulo Silveira, Guilherme Silveira e por mim (Rafael Cosentino) desde 2005.

Abordamos as principais estruturas de dados como Listas, Pilhas, Filas, Tabela de Espalhamento (Hash) e Mapas, e os algoritmos para a manipulação das mesmas. Há ainda tópicos como Recursão, Ordenação (selection-sort, insertion-sort, quick-sort e merge-sort), Pesquisa (sequencial e binária), Busca em Largura, Busca em Profundidade e Consumo de Tempo.


Lista ligada na memória

Normalmente, o desenvolvedor tem um conhecimento superficial sobre as estruturas de dados, sabendo mais ou menos como utilizar as que já estão prontas, sem saber como elas funcionam por dentro, e o que é muito pior, sem saber para quais tipos de problemas cada estrutura é eficiente. Esse conhecimento superficial não basta para desenvolver uma boa aplicação.

Na apostila, mostramos casos em que fica claro como a escolha de uma estrura errada para um determinado problema pode prejudicar o desempenho de uma aplicação ou até mesmo tornar inviável a utilização da mesma. Com alguns exemplos e só um pouquinho de teoria de Ciência da Computação veremos que alguns problemas levariam séculos (séculos de verdade!!!) para serem resolvidos pelo computador se a escolha da estrutura fosse errada e alguns segundos com uma estrutura adequada. E iremos mais afundo, veremos que uma implementação ruim de uma determinada estrutura pode obter resultados desastrosos.


Tabela de espalhamento (hash)

Também, salientaremos a idéia do reaproveitamento. Não precisamos reinventar a roda: mostramos, por exemplo, como implementar uma Pilha ou uma Fila reaproveitando uma Lista. Além disso tudo, mostraremos as implementações do Java para as estrutura de dados do nosso curso. Essas implementações são bem semelhantes as que iremos fazer do zero durante o curso.

O material ainda está na versão beta, ainda faltam alguns poucos tópicos, algumas figuras e um pouco de texto. Além da qualidade técnica, estamos investindo muito na qualidade visual do material; o Tiago Allen Marques de Oliveira, nosso desinger, está preparando imagens fantásticas para apostila.