Jak pożenić Gradle'a z Javą 9

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

Informatyka

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:

Ś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.

Tomasz Jędrzejewski

Programista Javy, lider techniczny. W wolnych chwilach podróżuje, realizując od kilku lat projekty długodystansowych wypraw pieszych.

Autor zdjęcia nagłówkowego: Jared Tarbell, CC-BY-2.0

zobacz inne wpisy w temacie

Informatyka

poprzedni wpis Git subtree następny wpis ChuckNorrisException

Komentarze (1)

Skomentuj

Od 3 do 40 znaków.

Wymagany, anonimizowany po zatwierdzeniu komentarza.

Odpowiedz na pytanie.

Edycja Podgląd

Od 10 do 8000 znaków.

Wszystkie komentarze są moderowane i muszą być zatwierdzone przed publikacją.

Klikając "Wyślij komentarz" wyrażasz zgodę na przetwarzanie podanych w nim danych osobowych do celów moderacji i publikacji komentarza, zgodnie z polityką prywatności: polityka prywatności