No último mês de outubro ocorreu, em São Francisco, Califórnia, o JavaOne 2015, conferência anual do Java realizada pela Oracle. Esta edição contou com mais de 400 sessões, incluindo apresentações técnicas, hands-on, tutoriais, keynotes e sessões de discussão. Em um dos keynotes mais aguardados, Mark Reinhold, arquiteto-chefe da plataforma Java, utilizou todo o seu tempo para falar sobre o Projeto Jigsaw. Ainda no evento, foi realizada uma série de workshops para mostrar o estado atual do desenvolvimento das funcionalidades trazidas pelo recurso e, assim, aumentar o entendimento e o feedback da comunidade sobre elas. Essa maior exposição do projeto Jigsaw deixa clara sua relevância para a tecnologia Java e a importância que a Oracle está dando ao assunto.
Mas, afinal, o que é esse tal Projeto Jigsaw? É um projeto para a adição de funcionalidades de modularização à plataforma Java. Os dois principais objetivos são: em primeiro lugar, a definição e a implementação de um modelo de módulos que possa ser utilizado no desenvolvimento de novas aplicações; e, por último, mas não menos importante, a modularização do JRE e do JDK em si, utilizando esse mesmo modelo.
Caso você já tenha estudado ou utilizado OSGi, deve estar familiarizado com o desenvolvimento modular e deve estar, também, se perguntando o motivo de tanto barulho em torno do Projeto Jigsaw. A resposta para esse questionamento, no entanto, é bem simples: além da facilidade de se ter a funcionalidade nativamente, o motivo pelo qual se decidiu implementar a solução dentro da plataforma é o fato de só assim ser possível modularizar a própria plataforma.
Para entendermos melhor o Projeto Jigsaw e suas implicações para os desenvolvedores Java, primeiramente falaremos sobre as motivações por trás dos principais objetivos: o modelo de módulos e a modularização do JRE e do JDK. Em seguida, passaremos por um breve histórico do projeto, desde suas origens no OSGi, até sua estrutura atual e os adiamentos que ocorreram em sua entrega. Falaremos também sobre compatibilidade, o que pode afetar principalmente os desenvolvedores que utilizam recursos internos do JDK, que deveriam ser utilizados somente pelos desenvolvedores da plataforma. Para fechar a parte teórica do artigo, analisaremos algumas deficiências do projeto, como a ausência de um mecanismo para o controle de versões dos módulos. Logo após, teremos uma parte prática, com exemplos que visam facilitar o entendimento e mostrar o poder dessa nova tecnologia. Assim, será construída uma aplicação de linha de comando que executa um simples cálculo de adição. A partir disso, a aplicação será dividida em módulos, para que seja possível ver o relacionamento e as restrições entre eles, e ao final, será gerada uma imagem de JRE contendo somente os módulos da plataforma utilizados pela nossa aplicação.
Modelo de Módulos
Atualmente, os modificadores de acesso Java desempenham muito bem seu papel no encapsulamento das classes. Porém, isso ocorre somente quando as classes envolvidas estão no mesmo pacote. Se uma classe precisa ser acessada por outra classe localizada em um pacote diferente, ela precisa necessariamente ser pública. Além de reduzir a segurança, essa limitação contribui em muito para o JAR Hell (vide BOX 1). A ideia no Projeto Jigsaw é que os módulos sirvam como uma camada adicional de abstração, acima do nível de package, permitindo que se declare quais são os pacotes que serão exportados para módulos que dependam do módulo que está sendo desenvolvido. A estrutura de um módulo pode ser vista na Figura 1. Com isso, os pacotes que não estiverem declarados como exportados ficarão visíveis somente por classes que estejam dentro do mesmo módulo. Quando analisamos esse objetivo mais detalhadamente, fica claro que ganhamos além de segurança, desempenho, já que o escopo para a busca de classes no tempo de execução será reduzido somente às classes que são exportadas.
Figura 1. Estrutura de um módulo.
BOX 1. JAR Hell
JAR Hell é como são conhecidos os problemas decorrentes do conflito entre versões de uma ou mais classes quando uma aplicação Java é executada. Quando estão presentes no classpath mais de uma versão da mesma classe, a JVM utiliza a classe que for encontrada primeiro. No entanto, não necessariamente essa é a versão da classe que deve ser utilizada pelo trecho de código que está sendo executado. Isso pode fazer com que a aplicação gere algum erro ou, o que é pior, tenha um comportamento diferente do esperado e traga grandes prejuízos. Embora pareça algo que não ocorra com frequência, é muito fácil exemplificarmos esse cenário com um caso concreto. Supondo que sua aplicação utilize Hibernate (que tem o dom4j como dependência) e que você também queira utilizar o dom4j em uma outra funcionalidade, caso você utilize uma versão diferente daquela que é referenciada pelo Hibernate, você pode acabar com os JARs das duas versões no classpath da sua aplicação. Nesse caso, qual versão da classe será utilizada pelo código que você desenvolveu? É difícil saber. Sua aplicação acaba de entrar no “Inferno dos JARs”! Assim, ela poderá ter diferentes comportamentos em diferentes ambientes e talvez você comece a ver os sintomas da síndrome do “Na minha máquina fun ...