Zielony Smok - logo witryny

Narzędzie do włączania analizatora zależności klas Java.

Narzędzie jdeps pokazuje zależności na poziomie klasy lub poziomie pakietu.

Opcje narzędzia określają to co znajdzie się na wyjściu.

Polecenie jdeps domyślnie drukuje zależności na wyjście systemowe.

Polecenie może generować zależności języku DOT (szczegóły dalej w tekście).

Składnia

jdeps [options] path …

path – ścieżka do pliku .class, folderu albo pliku archiwum JAR do przeanalizowania.

[options] – przedstawione poniżej w czterech tabelach

  • opcje ogólne
  • opcje analizy zależności modułów
  • opcje filtrowania zależności
  • opcje filtrowania klas do przeanalizowania
Opcje ogólne
[options] Opis
-? albo -h albo --help Drukuje tekst pomocy dla jdeps
-dotoutput dir albo --dot-output dir Opcja specyfikuje folder, w którym należy umieścić plik *.dot (plik języka DOT). Jeśli ta opcja jest użyta, dla każdego pliku archiwum name.jar generowany jest plik name.dot zawierający wylistowane zależności. Ponadto generowany jest jeden zbiorczy plik summary.dot, który listuje zależności pomiędzy plikami umieszczonymi w archiwum.
-s albo -summary Drukuje wyłącznie podsumowanie
-v albo -verbose Drukuje zależności dla wszystkich klas. Jest ekwiwalentem ustawienia opcji filtrowania -verbose:class -filter:none
-verbose:package Drukuje zalezności na poziomie pakietów, domyślnie wykluczając zależności w obrebie tego samego archiwum.
-verbose:class Drukuje zależności na poziomie klasy, domyślnie wykluczając zależności w obrębie tego samego archiwum.
-apionly albo --api-only Ogranicza analizę do API, np. tylko zależności między sygnaturami publicznych i chronionych członków klasy włączając typ pola, typy parametrów metod, typ zwracany i sprawdzane typy wyjątków.
-jdkinternals albo --jdk-internals Znajduje zależności na poziomie klasy w wewnętrzych API JDK. Ta opcja domyślnie analizuje wszystkie klasy wyspecyfikowane w opcji --classpath i plikach wejściowych chyba, że zostanie użyta opcja -include. Ta opcja nie może być użyta z opcjami -p, -e i -s.
-cp path albo -classpath path albo --class-path path Specyfikuje scieżkę dostepu do plików klas.
--module-path module-path Specyfikuje ścieżkę dostepu do plików zmodularyzowanych klas.
--upgrade-module-path module-path Specyfikuje ścieżkę do nowszej wersji modułu
--system java-home Specyfikuje ścieżkę do modułów alternatywnego systemu.
--add-modules module-name[, module-name...] Dodaje moduły do zestawu do przeanalizowania.
--multi-release version Specyfikuje wersję dla wielowersyjnych plików JAR. version musi być liczbą >=9 albo bazą.
-q albo -quiet Nie pokazuje brakujących zależnosci z wyjścia opcji -generate-module-info (patrz następna tabelka)
-version albo --version Drukuje informację o wersji

 

Opcje analizy zależności między modułami
[options] Opis
-m module-name albo --module module-name Specyfikuje główny moduł do analizy.
--generate-module-info dir Generuje plik module-info.java i umieszcza go we wskazanym folderze. Wyspecyfikowane pliki JAR będą analizowane. Ta opcja nie może być użyta z opcją --dot-output ani z --class-path. Dla modułów otwartych należy użyć opcji --generate-open-module
--generate-open-module dir Generuje plik module-info.java dla wyspecyfikowanego pliku JAR w folderze wyspecyfikowanym jako moduły otwarte. Ta opcja nie może być użyta z opcjami --dot-output ani --class-path
--check module-name [, module-name...] Analizuje zależności podanych modułów. Drukuje opis modułu (module descriptor), wynikowe zalezności modułu i graf po redukcji przejścia. Identyfikuje również nieuzte eksporty kwalifikowane.
--list-deps Listuje zależności modułu i nazwy pakietów wewnętrznego API JDK – jeśli są użyte. Opcja tranzytywnie analizuje biblioteki w ścieżce klas jeśli są przywoływane. Aby analiza zależności nie była tranzytywna należy użyć opcji --no-recursive.
--list-reduced-deps Działa jak opcja --list-deps, ale bez listowania implikowanych odczytów krawędzi z wykresu modułu. Jeśli moduł M1 czyta M2, a M2 requires transitive M3, wtedy czytanie M3 przez M1 jest implikowane i nie jest pokazywane w grafie.
--print-module-deps To samo co --list-reduced-deps z drukowaniem listy zależności modułów oddzielonych przecinkami. Wyjście może być użyte przez opcję --add-modules narzędzia jlink w celu utworzenia obrazów klienta, które zawierają te moduły i ich tranzytywne zależności.
--ignore-misssing-deps Ignoruje brakujące zalezności.

 

Opcje filtrowania zależności
[options] Opis
-p pkg_name albo -package pkg_name albo --package pkg_name Znajduje zależności dopasowane do podanej nazwy pakietu. Ta opcja może być użyta wielokrotnie dla różnych pakietów. Opcje -p i -e wzajemnie sie wykluczają.
-e regex albo -regex regex albo --regex regex Znajduje zależności dopasowane do wzorca. Opcje -p i -e wzajemnie sie wykluczają.
--require module-name Znajduje zalezności dopasowując nazwę podanego modułu (może wystąpić wielokrotnie). Opcje --package, --regex oraz --require wzajemnie się wykluczają
-f regex albo -filter regex Filtruje zależności dopasowane do podanego wzorca. W przypadku wielokrotnego użycia wybrany będzie ostatni.
-filter:package Filtruje zależności w obrębie pakietu. Opcja domyślna.
-filter:archive Filtruje zależności w obrębie podanego pliku archiwum.
-filter:module Filtruje zależności w obrebie podanego modułu.
-filter:none Nie zostanie użyte filtrowanie filter:package ani -filter:archive. Opcja -filter zostanie zastosowana.
--missing-deps Znajduje brakujące zależności. Nie może być użyta z opcjami -p, -e ani -s.

 

Opcje filtrowania klas do przeanalizowania
[options] Opis
-include regex Opcja ogranicza analizę do klas dopasowanych do wzorca. Może być użyta razem z opcjami -p i -e, które stosują wzorzec do zależności.
-P albo -profile Pokazuje profil zawierający pakiet.
-R albo --recursive Rekurencyjnie trawersuje wszystkie zależności czasu wykonywania. Opcja -R implikuje użycie opcji -filter:none. Jeśli opcje -p, -e lub -f są wyspecyfikowane, analizowane są tylko dopasowane zalezności.
--no-recursive Nie trawersuje zależności rekurencyjnie.
-I albo --inverse Analizuje zależności dla innych podanych opcji, a następnie znajduje artefakty, które bezpośrednio lub pośrednio zależą od dopasowanych węzłów. Jest to ekwiwalent inwersji analizy widoku czasu kompilacji i wydrukownia podsumowania. Ta opcja musi być użyta z opcją --require, --package lub --regex.
--compile-time Analizuje widok czasu kompilacji zależności tranzytywnych, takich jak widok czasu wykonywania opcji -R. Analizuje zalezności dla innych podanych opcji. Jeśli zalezność zostanie znaleziona w folderze, pliku archiwum lub module – wszystkie klasy w takim archiwum są analizowane.

Przykład (linia poleceń)

Do analizy użyjemy przedmodułowego pliku biblioteki jMusic1.6.3.jar. Oczywiście możesz tez wybrać nowszy plik.

Plik umieszczamy na dysku C:/assets/jdeps/jMusic1.6.3.jar

Uruchamiamy linię poleceń.

Wpisujemy komendę (Rys. 1):

jdeps - narzędzie JDK
Rys. 1. Polecenie 1

Na ekranie widzimy polecenie i fragment dość długiego listingu zależności.

Przykład (linia poleceń, DOT)

Wpisujemy komendę (Rys. 2) powodującą przekazanie wyniku analizy do pliku DOT w folderze C:/jtools09

jdeps - narzędzie JDK
Rys. 2. Polecenie 2

We wskazanym folderze pojawią się dwa pliki (Rys. 3):

jdeps - narzędzie JDK
Rys. 2. Polecenie 2

Oba pliki są tekstowe. Zdecydowanie lepiej jest otworzyć je w edytorze Notepad++ niż np. Word (stała szerokość).

Pierwszy plik zawiera (Rys. 4):

jdeps - narzędzie JDK
Rys. 4. Zawartość pliku jMusic1.6.3.jar.dot (fragment)

Drugi plik zawiera podsumowanie (Rys. 5):

jdeps - narzędzie JDK
Rys. 5. Zawartość pliku summary.dot

Na stronie https://graphs.grevian.org/graph znajdziemy generator wykresów DOT online.

Po wprowadzeniu kodu z pliku summary.dot (zob. Rys. 5) otrzymamy wykres zależności (Rys. 6).

jdeps - narzędzie JDK
Rys. 6. Wykres zależności z pliku summary.dot

Jeżeli chcemy samodzielnie wykreślać zależności DOT i inne w artykule Wikipedii DOT (graph description language)
znajdziemy więcej informacji o języku DOT oraz informacje o narzędziach i programach pozwalających na samodzielne wykreślanie.

Przykład (ToolProvider)

Polecenie możemy wykonać z poziomu klasy Java (jdeps.TP_jdeps1)

package jdeps;

import java.util.Optional;
import java.util.spi.ToolProvider;

public class TP_jdeps1 {
    public static void main(String[] args){
        Optional<ToolProvider> jdeps = ToolProvider.findFirst("jdeps");
        jdeps.ifPresent(toolProvider -> toolProvider.run(System.out, System.err, "C:/assets/jdeps/jMusic1.6.3.jar"));
    }
}

Drugie polecenie możemy wykonać z poziomu klasy Java (jdeps.TP_jdeps2)

package jdeps;

import java.util.Optional;
import java.util.spi.ToolProvider;

public class TP_jdeps2 {
    public static void main(String[] args) {
        Optional<ToolProvider> jdeps = ToolProvider.findFirst("jdeps");
        jdeps.ifPresent(toolProvider -> toolProvider.run(System.out, System.err, "-dotoutput", "C:/assets/jdeps", "C:/assets/jdeps/jMusic1.6.3.jar"));
    }
}

Wynik wykonania jest dokładnie identyczny jak w przykładach użycia przy pomocy linii poleceń.

Przykład (ProcessBuilder)

Oba powyższe komendy zostały wykonane w klasach jdeps.PB_jdeps1 oraz tool_jdeps.PB_deps2.

  package jdeps;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class PB_jdeps1 {
    public static void main(String[] args){
        try {
            ProcessBuilder pb = new ProcessBuilder();
            pb.command("jdeps", "C:/assets/jdeps/jMusic1.6.3.jar");
            pb.redirectError(ProcessBuilder.Redirect.INHERIT);
            Process p = pb.start();
            BufferedReader r = p.inputReader();
            String line;
            while ((line = r.readLine()) != null) {
                System.out.println(line);
            }
          int exitCode = p.waitFor();
           System.out.println("\nExited with code : " + exitCode);
            r.close();
            p.destroy();
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }
    }
}
package jdeps;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class PB_jdeps2 {
    public static void main(String[] args) {
        try {
            ProcessBuilder pb = new ProcessBuilder();
            pb.command("jdeps", "-dotoutput", "C:/assets/jdeps", "C:/assets/jdeps/jMusic1.6.3.jar");
            pb.redirectError(ProcessBuilder.Redirect.INHERIT);
            Process p = pb.start();
            BufferedReader r = p.inputReader();
            String line;
            while ((line = r.readLine()) != null) {
                System.out.println(line);
            }
            int exitCode = p.waitFor();
            System.out.println("\nExited with code : " + exitCode);
            r.close();
            p.destroy();
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }
    }
}

Wynik jest identyczny.