Chainsaw się rozwija

Chainsaw się rozwija

Wieści z frontu prac nad dodaniem obsługi modułów Javy 9 do Gradle'a dzięki wtyczce Gradle Chainsaw Plugin.

czwartek, 15 marca 2018

Informatyka

We wrześniu ubiegłego roku pojawiła się Java 9, a wraz z nią system modułów znany też pod roboczą nazwą Jigsaw. Wprowadza on fundamentalne zmiany w działaniu aplikacji - maszyna wirtualna nie traktuje już aplikacji jako jednego, wielkiego "wora" na klasy, które mogą bez przeszkód wszędzie sięgać. Poszczególne elementy składowe, zwane "modułami" są teraz fizycznie izolowane od siebie, a jako ich twórcy mamy wpływ na to, jakie elementy API będą widoczne dla innych. System modułów całkowicie zastępuje klasyczną flagę --classpath, a to niestety oznacza problemy dla istniejących systemów budowania, które muszą nauczyć się pracować w "nowej" rzeczywistości.

Od października rozwijam wtyczkę Gradle Chainsaw Plugin dodającą obsługę modułów do Gradle'a, który jak dotąd nie dorobił się stosownego wsparcia i rzut oka na Githuba jasno pokazuje, że upłynie jeszcze sporo czasu, zanim to się stanie. Projekt zaczął się jako fork bardzo ubogiego projektu experimental-jigsaw będącego raczej luźnym eksperymentem jednego z developerów niż poważną inicjatywą. Od tamtego czasu z oryginalnego kodu zostało niewiele. Całkowicie przebudowałem wewnętrzną architekturę wtyczki i sukcesywnie dodawałem obsługę kolejnych przypadków użycia. Kilkadziesiąt testów integracyjnych odpowiada za to, by nie zepsuć niczego, co już działało, a pokrycie kodu testami sięga 95%. Obecnie wtyczka jest używalna i da się przy jej pomocy zbudować całkiem sporo projektów. Zaczęły już spływać zgłoszenia błędów od innych programistów, a dzisiaj otrzymałem pierwszy pull request dodający obsługę TestNG. Innymi słowy, wspaniale jest na nowo włączyć się w nurt open-source :).

Obsługiwane taski

Celem projektu jest rekonfiguracja istniejących tasków Gradle'a tak, aby używały systemu modułów zamiast --classpath. Na dzień dzisiejszy wspierane są następujące polecenia:

  • compileJava - kompilacja źródeł Javy
  • compileTestJava - kompilacja źródeł testów,
  • test - uruchamianie testów jednostkowych, z automatycznym wykrywaniem JUnit 4/5,
  • run - uruchamianie aplikacji z poziomu Gradle'a,
  • javadoc - generowanie dokumentacji.

Częściowo wspierane jest też zadanie installDist, które m.in. generuje skrypty startowe dla systemów uniksowych i Windowsa.

Nowy DSL

Oto przykład konfiguracji wtyczki pokazujący jej aktualny stan, obowiązujący od wersji 0.3.0:

plugins {
  id 'com.zyxist.chainsaw' version 'x.y.z'
}

javaModule.allowModuleNamingViolations = false
javaModule.extraTestModules = ['org.mockito']
javaModule.hacks {
   opens('java.base', 'java.lang', 'com.google.guice')
   reads('com.example.mymodule', 'ALL-UNNAMED')
   exports('com.example.mymodule', 'com.example.mymodule.somePackage', 'com.example.anotherModule')
   patches('com.google.code.findbugs:jsr305', 'jsr250.api')
}

dependencies {
    patch 'com.google.code.findbugs:jsr305:1.3.9'

    compile 'javax.annotation:jsr250-api:1.0'
    compile 'com.google.guava:guava:23.2-jre'

    testCompile 'org.mockito:mockito-core:x.y.z'
}

Oto jej możliwości:

  • automatyczne wykrywanie nazwy modułu ze źródeł module-info.java,
  • weryfikacja zgodności nazwy modułu z konwencjami (odwrotny DNS, od głównego pakietu),
  • dodawanie modułów testowych takich, jak Mockito (testy nie mają własnego modułu, więc nie można użyć deskryptora),
  • patchowanie modułów do łatania package splitów,
  • dodawanie flag --add-opens, --add-reads, --add-exports,
  • obsługa projektów wielomodułowych.

Plany na przyszłość

Obecnie koncentruję się na poprawieniu obsługi zadania installDist. Na Githubie otwartych jest kilka zgłoszeń błędów dot. niewłaściwie wygenerowanych flag w skryptach startowych. Kolejnym krokiem będzie dodanie możliwości generowania modułowych obrazów aplikacji. Jest to zupełnie nowy format dystrybucji kompletnych aplikacji, który pojawił się w Javie 9 (JEP-220), znacznie zoptymalizowany w stosunku do tzw. über-JAR'ów i wspierający moduły. Nowy format jest czymś dużo więcej niż tylko kolekcją archiwów JAR, bowiem zawiera również samą maszynę wirtualną i wszystkie wykorzystywane przez aplikację moduły JDK. Taki obraz możemy uruchomić na dowolnej maszynie bez konieczności instalacji Javy.

Zaglądając dalej w przyszłość, moim marzeniem jest dodanie obsługi tzw. multirelease JAR-s. Od zwykłych JAR-ów odróżnia je to, że zawierają klasy skompilowane dla kilku wersji Javy jednocześnie, i to w sposób wstecznie kompatybilny: tak utworzone archiwum będzie działało zarówno z Javą 8, jak i 10. Wyzwaniem jest kompilacja takiego projektu, która musi się składać z kilku faz, a także podmiana tylko tych klas, dla których dysponujemy "nowszymi" źródłami. Nie mam także wciąż pomysłu, jak rozwiązać kwestię testowania takiego projektu, ani jak mogłoby wyglądać wsparcie ze strony środowisk programistycznych.

Podsumowanie

Jeśli jeszcze nie bawiłeś się modułami Javy 9, to jest na to odpowiednia pora. Istnieją już narzędzia pozwalające na budowanie modułowych projektów, a coraz większa liczba bibliotek dostarcza nie tylko deklaracje nazwy automatycznych modułów w manifestach, ale i prawdziwe deskryptory. Ze swej strony mogę polecić jeden z moich wcześniejszych artykułów, który jest wprowadzeniem w tematykę Jigsaw. A oto garść przydatnych odnośników, w tym wspomniany artykuł:

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: Petra Blume, CC0

Komentarze (0)

Skomentuj

Od 3 do 40 znaków.

Wymagany, nie będzie publikowany.

Odpowiedz na pytanie.

Edycja Podgląd

Od 10 do 8000 znaków.

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