Novo Treinamento FJ-16: Laboratório Java com Swing, XML e Testes

Por Sérgio Lopes em 14/08/08

FJ-16 Laboratório SwingDepois de aprender bem o Java, uma pergunta comum de alunos e de usuários do GUJ é: como adquirir experiência e boas práticas? Com esse intuito criamos um novo treinamento, onde desenvolvemos uma aplicação desktop com Swing, que faz análise técnica da bolsa de valores, através de gráficos, usando como fonte uma base XML. É o FJ-16: Laboratório Java com Swing, XML e Testes.

FJ16

O mais interessante é que, durante o desenvolvimento da aplicação, aprendemos a aplicar diversos design patterns (como o Decorator entre indicadores), utilizamos testes unitários com JUnit, conhecemos as ferramentas Ant e Maven, aplicamos reflection e anotações, além de sempre estar refatorando o código inúmeras vezes.

Nesse treinamento, são colocados em prática também diversos conceitos da linguagem que usamos no dia-a-dia, como manipulação de datas, de XML, classes anônimas, classes internas, uso do log4J, entre outros.

Veja a ementa completa na página do treinamento. Temos turmas agendadas para final de agosto e começo de setembro. Entre em contato conosco para mais informações.

Effective Java: segunda edição

Por Paulo Silveira em 25/07/08

Effective Java Como sabemos, a segunda edição do Effective Java foi publicada. O autor é Joshua Bloch, um dos principais responsáveis pelo generics do Java, e atualmente chief java architect no Google. Esse livro é dividido em 78 itens, cada um com cerca de 3 páginas, atacando um ponto específico do java e orientação a objetos, explicando uma boa ou má prática. Simplesmente incrível, durante a leitura você sempre reconhece muita coisa que já aprendeu durante sua experiência de desenvolvimento.

Essa nova edição está estendida e revista, para cobrir as grandes mudanças do Java 5. Esse, juntamente com outros dois livros (e atualmente incluiríamos também o The Mythical Man-month), são de extrema importância para todo desenvolvedor na nossa opinião.

O Fernando Boaglio tem um resumo em seu blog, sobre todos os itens dessa nova versão. A Vanessa Sabino publicou anos atrás um resumo completo sobre a primeira edição, que você pode conferir na coluna da direita do seu blog.

O Fernando também postou no GUJ um link para uma excelente entrevista do Joshua Bloch, onde ele tenta resumir as más práticas, o java inefetivo: otimização prematura, e escrever o próprio código quando bibliotecas boas já existem. Além disso, Joshua Bloch é categório sobre a grande importância dos testes unitários: “Unit testing is key. And writing your tests first is a great thing.

Lendo essa nova edição e relembrando muito da edição anterior, escolhi aqui quatro itens que considero vitais, e vou falar sucintamente sobre cada um deles. Curiosamente todos os selecionados aqui já existiam na edição anterior, e estão mais relacionados a design que a idiomismos da linguagem, mas isso não tira a importância dos outros aqui não citados. Esses itens são muito debatidos no capítulo de Tópicos em Orientação a Objetos no nosso trienamento de Design e Arquitetura de projetos Java. Vamos a eles:

Item 15: Minimize mutabilidade

Classes imutáveis possuem uma série de vantagens: fáceis de manter, não possuem efeitos colaterais e acima de tudo são thread safe. Uma classe deve ser imutável a não ser que você tenha muito bons motivos para isso. Mesmo se não for possível tornar sua classe imutável, minimize a quantidade de métodos que alteram o estado do objeto. Um objeto previsível é muito mais simples de manter. Joshua Bloch cita String, BigInteger e diz que java.util.Date e java.awt.Point deveriam ter sido criadas imutáveis! Muitas APIs novas abusam da imutabilidade, como a Joda Time, classes wrapper, Money and Time do Eric Evans, etc. Aliás, é com o slogan da imutabilidade que linguagens como clojure e erlang tem chamado tanta atenção. Leia também essa citação no blog do Renato Lucindo.

Item 16: Favoreça composição em vez de herança

Esse é um tópico que já foi discutido anteriormente nesse post. O fato é o seguinte: é muito fácil usar herança de maneira errada, como é o caso de Stack extends Vector e Properties extends Hashtable. Mesmo quando usada corretamente, herança pode causar efeitos colaterais com muita facilidade, sendo que utilizar interfaces e composição pode substitui-la por completo, com o pequeno acréscimo de algumas linhas de delegação. Esse item também é citado no livro Design Patterns como um dos dois princípios básicos do bom design orientado a objetos.

Item 47: Conheça e use as bibliotecas!

Você conhece a ArrayDeque do java 6? Sabia que a java.util.Scanner pode ler facilmente arquivos com formatos caseiros, e já trazer para você doubles, Strings e até mesmo BigDecimals? Que JAXB e JAXWS podem agora ser usados apenas com Java SE? Sabia que a Collections possui hoje métodos para calcular a frequência de um elemento e inverter a ordem de um Comparator?. Conhecer bem a biblioteca padrão do Java pode te salvar de escrever muito código já existente, testado e de qualidade. java.io, java.lang e java.util são APIs que funcionam como base para todo desenvolvedor e merecem um estudo aprofundado.

Item 52: Refira a objetos pelas suas interfaces
Sem dúvida uma boa prática mais que necessária. Através dela conseguimos diminuir muito o acoplamento entre classes, deixando apenas uma fina camada entre elas: as interfaces. Sempre usar InputStream em vez de se acoplar em FileInputStream, sempre usar List em vez de se acoplar a ArrayList. Muitas vezes podemos ir mais longe, nesse último caso Collection pode ser o suficiente, ou até mesmo Iterable! Algumas pessoas levam isso tão a sério que nunca criam uma única classe concreta que não implemente uma interface. Esse item também é citado no livro Design Patterns, e é o outro princípio básico do bom design orientado a objetos desta forma: “Programe voltado a interface, e não a implementação“.

Ainda existem itens fundamentais sobre Enums, Exceptions, Concorrência e Generics. Esse livro é realmente importante na sua cabeceira. Boa leitura!

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.

Entendendo o serialVersionUID

Por Paulo Silveira em 01/04/08

O serialVersionUID é uma dúvida constante entre muitos desenvolvedores. Afinal, quando e para que exatamente usá-lo? Devo gerar um número aleatório bem grande, ou um número qualquer? Essas perguntas são comuns, e ao desenvolvedor experiente é necessário conhecer a fundo esse detalhe do processo de serialização do Java.

Quando um objeto é serializado no Java, essa sequência de bytes, além de conter seus atributos de instância não transientes, carrega consigo um número que indentifica a “versão” da classe que foi usada durante o processo. Esse é o chamado serialVersionUID, ou seja, o indentificador de versão de serialização de uma classe. Esse número é utilizado para saber se o objeto que estamos recuperando é de uma versão “compatível” com a versão da classe que foi utilizada quando serializamos o objeto: em outras palavras, os arquivos .class não precisam ser necessariamente os mesmos para que o processo de serialização ocorra com sucesso.

Por exemplo, considere a seguinte classe Usuario:

package br.com.caelum;

public class Usuario implements Serializable {
  private String login;
}

Essa classe possui o serialVersionUID igual a 2806421523585360625L. Esse número não é aleatório! Ele é um hash (SHA) calculado em cima dos nomes dos seus atributos, e assinaturas dos métodos em uma ordem bem definida pela especificação do processo de serialização. E como eu sei esse número? O JDK vem com a ferramenta serialver, que implementa esse mesmo hash:

serialver br.com.caelum.Usuario

Se o serialVersionUID utilizado durante a serialização não bater exatamente com o serialVersionUID da classe que está sendo usada para recuperar essa informação, uma exception é lançada: java.io.InvalidClassException.

Por exemplo, se adicionarmos um novo atributo na nossa classe Usuario:

public class Usuario implements Serializable {
  private String login;
  private String senha;
}

Agora teremos o serialVersionUID valendo 416295346730660862L. Caso você serialize um Usuario com a primeira classe aqui definida, e tentar recuperar essa informação usando essa nova versão de classe, receberemos a conhecida java.io.InvalidClassException. Esse é o comportamente que em muitos casos queremos, mas algumas vezes fazemos pequenas modificações na classe as quais percebemos que não impactarão no processo de serialização, e precisamos manter compatibilidade com a versão antiga daquela classe. Para isso, basta definirmos explicitamente qual é o nosso serialVersionUID, e no caso de querer manter compatibilidade com a classe Usuario anterior, vamos utilizar o valor de serialVersionUID que seria gerado pela JVM: 2806421523585360625L. O código ficaria:

public class Usuario implements Serializable {
  private static final long serialVersionUID = 2806421523585360625L;
  private String login;
  private String senha;
}

Às vezes recebemos um warning do Eclipse, e ele pede para que seja definido o serialVersionUID da classe em questão. Isso ocorre porque você implementa Serializable ou uma de suas mães a implementa. O Eclipse então te abre três opções: utilizar o @SurpressWarnings para você assumir o risco, usar um valor default, ou usar o valor gerado. O gerador de UIDs do Eclipse é exatamente o mesmo gerador utilizado pelo Java SE para criar os UIDs padrão! Reforçando, esse número não é um número aleatório!

serialVersionUID

Quando alguém esquece de manter o mesmo serialVersionUID para duas versões compatíveis de uma classe, podemos ter problemas em usar diferentes versões do software que são teoricamente compatíveis. Isso muitas vezes acontece em servidores de aplicação, e se seu cliente esta desatualizado em relação a versão dos jars necessários pelo servidor, podemos ter alguns InvalidClassExceptions que poderiam ser facilmente evitados se o serialVersionUID tivesse sido corretamente aplicado. Claro que algumas outras vezes as versões realmente não são compatíveis e a exception procede.

Esse grave problema pode acontecer mesmo usando classes do Java SE entre diferentes versões, como é o caso da classe java.text.AttributedCharacterIterator.Attribute (utilizada pela java.awt.Font). Do Java 1.3 para o Java 1.4 essa classe foi levemente alterada, e o serialVersionUID gerado pelo algoritmo da JVM desta classe mudou de -1514471214376796190L para -9142742483513960612L. Quando alguém serializava uma java.awt.Font em uma versão não podia desserializa-la em outra, sendo que as versões tecnicamente são compatíveis: a não definição explícita do serialVersionUID gerou um bug no Java SE. Como isto foi resolvido? Definiram o serialVersionUID como -1514471214376796190L, que é o valor que seria gerado pela JVM na versão anterior da classe.

Como então devemos proceder para escolher um serialVersionUID apropriado? É muito simples: se essa classe está nascendo neste momento, você pode se dar ao luxo de utilizar um serialVersionUID, como por exemplo:

public class Usuario implements Serializable {
  private static final serialVersionUID = 1L;
  private String login;
}

Porém se você está definindo o serialVersionUID de uma classe já em produção, e sabe que a mudança que está fazendo é compatível com a versão anterior, você deve utilizar o serialVersionUID que seria gerado pela JVM na primeira versão, como foi o caso aqui quando adicionamos o atributo senha na classe Usuario, e também foi o caso da correção do bug da classe java.text.AttributedCharacterIterator.Attribute. Quando você fizer uma alteração onde percebe que o cliente precisará de atualização das classes envolvidas, basta definir um serialVersionUID diferente dos anteriormente utilizados.

Para completar, implementar uma interface que não define métodos (Serializable) e ser forçado a escrever um atributo sem um contrato mais burocrático é um tanto estranho em uma linguagem como o Java. Sem dúvida, se esse mecanismo todo tivesse sido inventado já com a existência de anotações, Serializable seria uma anotação e version um atributo dela, talvez obrigatório, criando algo como @Serializable(version=12345L). Boas serializações e invocações remotas!

Novidades do EJB 3.1 do futuro Java EE 6

Por Nico Steppat em 24/03/08

A especificação EJB 3.0 já está no mercado há quase 2 anos e simplificou bastante o desenvolvimento. O uso de anotações (XML opcional) e POJOs/POJIs são as características principais. EJB 3.0 faz parte da Java EE 5.

Ainda esse ano deve sair o Java EE 6 e, com ele, também uma atualização da especificação do EJB. Vamos ver quais são as novidades/melhorias propostas atualmente no rascunho do EJB 3.1:


Facilidades no desenvolvimento

1) Interfaces locais são opcionais.

Um session bean local pode ficar simples assim:


@Stateless
public class PedidoDAO {

  public void cadastra(Pedido pedido) {
    //código para cadastrar um pedido
  }
}

Não precisa mais da interface e da anotação @Local.

2) EJB’s dentro do war

Será possivel colocar um EJB3 num war, facilitando o packaging. Não é preciso criar um jar e ear separado, tudo pode ser dentro de um unico war. As classes ficam na pasta WEB-INF/classes, e se for usado um ejb-jar.xml, se encontra na pasta WEB-INF.


Novidades

1) Singleton Beans

A ideia é que você pode criar session beans que só existem uma única vez na sua aplicação. Assim é possível criar objetos como o ServletContext na aplicação web. Por exemplo:


@Singleton @ReadOnly
public class ApplicationContextBean implements ApplicationContext {

  @PostConstruct
  public void init() {
    //initializa o contexto da aplicação
  }

  //métodos, por exemplo getAttribute(String chave)
}

Repare a anotação @ReadOnly, declarando o EJB imutável. Também vai existir uma anotação @ReadWrite para singletons beans que podem ser alterados.

O método init() será executado quando o container inicializa a aplicação. Singleton components também serão EJBs e podem ser injetados, o que é uma grande vantagem em relação a ter de ficar preso ao método estático de lookup de um singleton, e uma boa prática de inversão de controle.

2) EJB Timer

Terá uma nova anotação @Schedule referente ao EJB timer para facilitar o agendamento. Por exemplo:



@Schedule(hour=”13”, dayOfMonth=”1”)
public void geraRelatorio() {/* …. */}

executa cada primeiro dia no mes as 13 horas. É um modelo bem superior aos atuais timers do EJB, porém ainda não tão completo quanto aos frameworks open source existentes, como o Quartz.

3) Chamadas assíncronas

Parecidos com Web Services, métodos num session beans também podem ser chamados assincronamente. Para isto serve a anotação @Asynchronous:


@Stateless @Remote(PedidoFacade.class)
public class PedidoFacadeBean implements PedidoFacade{

  @Asynchronous
  public void cadastra(Pedido pedido) {
    //código para cadastrar um pedido
  }

  @Asynchronous
  public Future autoriza(Pedido pedido) {
    //autoriza demora …..
  }
}

O segundo método devolve um object do tipo java.util.concurrent.Future que fornece métodos para verificar se o resultado já chegou.

O lançamento da versão 3.1, que teoricamente ocorrerá até o fim deste ano, deve acelerar ainda mais a adoção da plataforma Java EE 5/6 em relação ao uso das versões antigas J2EE.