Jak pożenić Gradle'a z Javą 9
Zbliża się premiera Javy 9 - wpis pokazuje, w jaki sposób współpracuje ona z systemem budowania Gradle.
wtorek, 13 czerwca 2017
Zbliża się premiera Javy 9, w której największą nowością ma być natywny system modułów: Jigsaw. Emocje związane z jego wprowadzeniem są ogromne, a przede wszystkim nie wiadomo czy nie zostanie on w ostatniej chwili wycofany z uwagi na dużo zastrzeżeń ze strony "dużych" graczy. Jeżeli przejdzie, będzie to największa zmiana architektoniczna w ekosystemie od lat, do której będzie musiała ustosunkować się większość narzędzi, bibliotek i frameworków. Niepewność powoduje jednak, że na kilka miesięcy przed premierą najważniejsze systemy budowania wciąż nie radzą sobie z JDK9. Na szczęście sytuacja nie jest beznadziejna i przy odrobinie wysiłku można zmusić je do skompilowania istniejących projektów. W tym wpisie pokażę, jak to zrobić dla Gradle'a.
Narzędzia
Do eksperymentów użyłem:
- JDK9 Early Access build 173 - do pobrania z http://jdk.java.net/9/
- Gradle 4.0 M2 - do pobrania z https://gradle.org/release-candidate
Ściągnąłem też najnowszą wersję developerską środowiska NetBeans 9.0, jednak ponieważ wsparcie dla Gradle'a zapewnia tu zewnętrzna wtyczka niezbyt dostosowana do tej wersji, w praktyce nie udało się nic zbudować i zdecydowałem się odłożyć ten temat na bok.
Konfiguracja Gradle'a
Liczba zmian w Javie sprawia, że obecne buildy Gradle'a nie działają bez kilku drobnych poprawek. Po pierwsze, musimy ustawić dwie zmienne środowiskowe:
JAVA_HOME=C:\Program Files\Java\jdk-9\
GRADLE_OPTS=--add-opens java.base/java.lang=ALL-UNNAMED
Dzięki pierwszej zmiennej Gradle wie, że ma odpalić się na Javie 9. Druga ze zmiennych konfiguruje dodatkowy przełącznik dla maszyny wirtualnej, w której będzie chodzić Gradle. Flaga --add-opens
została stworzona na potrzeby uruchamiania starszych aplikacji i pozwala ona pominąć weryfikację dostępu do zawartości dwóch wskazanych modułów z JDK. Jest to pełny dostęp, tj. zarówno widoczność ukrytych klas, jak i możliwość dostania się do nich przez refleksję.
Drugą poprawką jest wyłączenie trybu demona, który obecnie nie współpracuje z Javą 9, powodując wygenerowanie ExceptionInInitializerError
podczas startu. Otwieramy nasz plik gradle.properties
i dodajemy do niego jedną linijkę:
org.gradle.daemon=false
I to wszystko. Tak skonfigurowany Gradle jest w stanie zbudować dowolny istniejący (tj. napisany pod Javę 8) projekt na Javie 9, dzięki czemu możemy sprawdzić czy wszystko działa. Można to podpiąć pod Jenkinsa, a wtedy projekt będzie budował się po każdym merge'u.
Bonus: Jigsaw!
Jeżeli chcemy pobawić się modułami, sprawa robi się bardziej skomplikowana, bowiem aby to zadziałało, kompilator musi dostać zupełnie nowe parametry na wejściu. W idealnym świecie nie powinniśmy się tym w ogóle przejmować, gdyż powinien to za nas zrobić Gradle. Jednak na chwilę obecną nie zna się on na modułach i pozostaje nam co najwyżej dopisanie ich samodzielnie. Kod do tego przykładu można znaleźć na Githubie: https://github.com/zyxist/jdk9-gradle. Zajmijmy się najpierw projektem jdk9-sample
, który ma pełnić rolę biblioteki wystawiającej publiczne API i mającej implementację. Oto jego struktura katalogowa:
/src/main/java
/greetings
/com/zyxist/api
/SomeApi.java
/com/zyxist/impl
/SomeImplementation.java
/module-info.java
/build.gradle
Gdy korzystamy z Jigsaw, bezpośrednio w /src/main/java
muszą znaleźć się katalogi, których nazwa jest zgodna z nazwą modułu. Dopiero wewnątrz nich umieszczamy pakiety oraz plik module-info.java
zawierający opis naszego modułu. Będzie on bardzo prosty - bez zależności i eksportujący pojedynczy pakiet jako publiczne API:
module greetings {
exports com.zyxist.api;
}
Do zbudowania projektu używam następującego skryptu budowania:
plugins {
id 'java-library'
id 'maven-publish'
}
group 'com.zyxist.jdk9'
version '0.0.1-SNAPSHOT'
compileJava {
options.compilerArgs += ["--module-source-path=src/main/java"]
}
model {
components {
main(JvmLibrarySpec) {
targetPlatform 'java9'
}
}
}
publishing {
publications {
mavenJava(MavenPublication) {
from components.java
}
}
}
Powyższy skrypt wykorzystuje nowy DSL do budowania projektów javowych, który zadebiutował gdzieś w okolicach Gradle'a 3.4 (chodzi o element model
). Ma on kilka interesujących możliwości, a wśród nich jest emulacja projektu Jigsaw, która pozwala oddzielić API od implementacji już teraz. W zamyśle ma to służyć ułatwieniu późniejszej migracji projektów na Jigsaw, jednak póki co nie przekłada się w żaden sposób na możliwość kompilowania natywnych modułów. Dlatego ograniczyłem się tutaj jedynie do wskazania docelowej platformy.
Kluczowa do poprawnego działania jest linijka konfigurująca argumenty kompilatora. Ustawia ona flagę --module-source-path
, która - jak nietrudno się domyślić - mówi kompilatorowi, gdzie siedzą źródła naszego modułu. Tego typu argumenty powinien docelowo dodawać Gradle, a póki co zostaje nam ręczne hackowanie. Taki projekt możemy już zbudować standardową komendą gradle build publishToMavenLocal
.
W repozytorium na Githubie jest także drugi projekt, jdk9-application
, który korzysta z pierwszego projektu jako zależności. Niestety na tym możliwości współpracy Gradle'a z Jigsaw się obecnie kończą. Docelowo, Gradle powinien pobrać archiwum z repozytorium, a następnie sprawić, by Java widziała je jako moduł. Aktualnie tego nie robi, przez co przy próbie kompilacji dostajemy błędy o nieznanych symbolach. Uznałem, że w tym miejscu hackowanie powinno się zakończyć, ponieważ podawanie w skrypcie budowania ścieżek do lokalnego repozytorium z JAR-ami to nie jest najlepszy pomysł, nawet jak na obejście.
Podsumowanie
Mam nadzieję, że powyższe informacje pomogą Wam w przetestowaniu działania Waszych projektów na Javie 9. W międzyczasie czekamy na wieści dotyczące Jigsaw. 15 maja odbyło się nad nim publiczne głosowanie wśród 23 członków komitetu wykonawczego projektu Java, gdzie większość z nich zagłosowała przeciwko, z warunkami. Od tamtego momentu opiekunowie specyfikacji mieli 30 dni na wyjaśnienie i rozwiązanie spornych kwestii, a lada dzień poprawiony JSR-376 zostanie poddany pod ponowne głosowanie, który zadecyduje już o jego ostatecznym losie.
W przypadku dopuszczenia projektu Jigsaw, będzie bardzo mało czasu na dostosowanie istniejących narzędzi. Może okazać się, że po premierze Javy 9 będziemy musieli zaczekać jeszcze trochę na wsparcie ze strony Mavena i Gradle'a, a także środowisk programistycznych. Dopiero wtedy będzie możliwe myślenie nad migracją naszych projektów. A gdyby Jigsaw nie wszedł? Cóż... Java 9 to także wiele innych zmian, choć nie są one tak spektakularne. Z pewnością będzie to oznaczać wyrzucenie do kosza wielu lat pracy i zawód wśród wielu programistów, jednak w dłuższej perspektywie może to wyjść środowisku na dobre, skłaniając ludzi do lepszego słuchania siebie nawzajem i skupienia się na tych zmianach, które są naprawdę istotne.
Jeśli chodzi o moje odczucia, do Jigsaw mam umiarkowanie pozytywne nastawienie. Całe zamieszanie i brak wsparcia to sygnał ostrzegawczy, ale nie skreślam jeszcze tego projektu.
zobacz inne wpisy w temacie
Komentarze (1)
Tomasz Jędrzejewski
# sobota, 2 września 2017, 08:01
Zapraszam do lektury najnowszego wpisu na temat modułów: Zrozumieć moduły w Javie 9. W międzyczasie pojawił się też oficjalny poradnik na stronie Gradle'a: Building Java 9 modules @ Gradle.org