Como usar JARs não modularizados em um módulo do Java 9?

Você resolveu usar Java 9 no seu projeto e criou um módulo:

module br.com.alexandreaquiles.projeto {
}

Por padrão, todo módulo “puxa” o java.base, que disponibiliza pacotes como java.lang, java.math, java.util e java.io.

Vamos dizer que seu código usa o JDBC. Pra poder ter acesso a interfaces como Connection e PreparedStatement, você precisa dizer que usa o módulo java.sql:

module br.com.alexandreaquiles.projeto {
    requires java.sql;
}

JARs não modularizados

Agora, digamos que o seu projeto usa a biblioteca commonmark, responsável por renderizar arquivos Markdown.

Os desenvolvedores dessa biblioteca não criaram um module-info.java. Ou seja, o JAR do commonmark não está modularizado.

O que preciso colocar no requires pra usar classes dessa biblioteca no meu código?

Você precisa “puxar” o módulo org.commonmark:

module br.com.alexandreaquiles.projeto {
    requires java.sql;
    requires org.commonmark;
}

Automatic-Module-Name

Mas da onde vem esse nome?

Para todo JAR não modularizado, é criado um módulo automaticamente, que exporta todos os pacotes.

O nome desse módulo automático pode ser definido pelos desenvolvedores da biblioteca na propriedade Automatic-Module-Name do arquivo META-INF/MANIFEST.MF lá dentro do JAR.

É uma estratégia de compatibilidade em que o nome do módulo automático é informado explicitamente.

O conteúdo do META-INF/MANIFEST.MF de dentro do commonmark-0.11.0.jar é o seguinte:

Manifest-Version: 1.0
Automatic-Module-Name: org.commonmark
Built-By: bamboo-agent
Created-By: Apache Maven 3.3.9
Build-Jdk: 1.8.0_144

Por isso, pra puxar o módulo automático do commonmark para nosso módulo, usamos o nome org.commonmark.

jar –describe-module

Mas e quando os desenvolvedores da biblioteca não colocaram a propriedade Automatic-Module-Name no MANIFEST.MF?

É o caso da biblioteca jsoup, que serve pra manipular HTML em Java à la jQuery.

O nome do módulo automático do jsoup é simplesmente jsoup. Por isso, no nosso módulo, devemos fazer:

module br.com.alexandreaquiles.projeto {
    requires java.sql;
    requires org.commonmark;
    requires jsoup;
}

Agora, e esse nome de módulo, da onde vem?

Vem do nome do próprio JAR! No caso do jsoup, é jsoup-1.11.2.jar.

Perceba que o número de versão do JAR foi extirpado. A regra completa está na documentação do método ModuleFinder.of().

É difícil de adivinhar. Porém, o comando jar agora tem a opção --describe-module, que deve ser usada em conjunto com --file:

jar --file jsoup-1.11.2.jar --describe-module

O nome do módulo automático será exibido antes do @:

No module descriptor found. Derived automatic module.

jsoup@1.11.2 automatic
requires java.base mandated
contains org.jsoup
contains org.jsoup.helper
contains org.jsoup.internal
contains org.jsoup.nodes
contains org.jsoup.parser
contains org.jsoup.safety
contains org.jsoup.select

Os contains mostram os pacotes exportados.

Podemos executar também para o commonmark:

jar --file commonmark-0.11.0.jar --describe-module

Perceba que o Automatic-Module-Name é respeitado:

No module descriptor found. Derived automatic module.

org.commonmark@0.11.0 automatic
requires java.base mandated
contains org.commonmark
contains org.commonmark.internal
contains org.commonmark.internal.inline
contains org.commonmark.internal.renderer
contains org.commonmark.internal.renderer.text
contains org.commonmark.internal.util
contains org.commonmark.node
contains org.commonmark.parser
contains org.commonmark.parser.block
contains org.commonmark.parser.delimiter
contains org.commonmark.renderer
contains org.commonmark.renderer.html
contains org.commonmark.renderer.text

Um bug no Eclipse

Num projetinho de teste, tentei usar a API do Hibernate com o Eclipse Oxygen.2 (4.7.2) e deu pau! Com o Maven e no IntelliJ funcionou bonitinho.

O hibernate-jpa-2.1-api-1.0.0.Final.jar não tinha um Automatic-Module-Name e a saída do jar --describe-module era hibernate.jpa. Porém, o Eclipse não reconhecia esse nome de módulo!

Abri um bug, que já foi corrigido. Era um erro na detecção de nomes de módulos do JDT.

A versão com a correção é a Eclipse 4.8 Milestone 5, ainda não lançada.

Anúncios

Um comentário sobre “Como usar JARs não modularizados em um módulo do Java 9?

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s