Java 9 Modul Abhängigkeiten

Java 9 Bootcamp Logo

Im ersten Teil dieser Serie habe ich gezeigt, wie man mit Java 9 ein Modul baut, kompiliert und ausführt. Unser "Hello World" Modul nutzt aber die interessanten Eigenschaften des Modulsystems noch gar nicht. In diesem Teil unserer Blog-Serie sehen wir uns an, wie man Abhängigkeiten zwischen Modulen setzt.

Das Modul Greeter

Dazu bauen wir ein zweites Modul. Basispackage und Modulname sind "de.eppleton.greetings", unsere einzige Klasse heisst "Greeter", damit ergibt sich dieser Pfad:

src/de.eppleton.hello/de/eppleton/greetings/Greeter.java

Hier der Inhalt:

package de.eppleton.greetings;

public class Greeter {
    public static void greet(String who) {
        System.out.println("Hello "+who+"!");
    }
}

...und folgende module-info:

 module de.eppleton.greetings {
    exports de.eppleton.greetings;
 }

Mit dem "exports"-Statement erlauben wir anderen Modulen den Zugriff auf die Package "de.eppleton.greetings" (und damit auf unsere Klasse Greeter).

Jetzt kompilieren wir das Ganze:

javac -d modules/de.eppleton.greetings/ src/de.eppleton.greetings/module-info.java src/de.eppleton.greetings/de/eppleton/greetings/Greeter.java

Damit ist unser Modul fertig. Wir haben die Package de.eppleton.greetings exportiert. Daher kann unser erstes Modul die Klasse "Greeter" nutzen und die Methode "greet" aufrufen.

Abhängigkeiten definieren

Wir ändern nun unsere HelloWorld.java aus dem ersten Teil und verwenden die Greeter-Klasse:

package de.eppleton.hello;
import de.eppleton.greetings.Greeter;

public class HelloWorld {
    public static void main(String[] args) {
        Greeter.greet("modular world");
    }
}

Nun wollen wir diese Klasse erneut kompilieren. Vom letzten Blogeintrag wissen wir, dass in Java 9 statt dem classpath der module-path verwendet wird, daher geben wir diesen beim kompilieren an:

>javac --module-path modules -d modules/de.eppleton.hello src/de.eppleton.hello/de/eppleton/hello/HelloWorld.java src/de.eppleton.hello/module-info.java 
src/de.eppleton.hello/de/eppleton/hello/HelloWorld.java:2: error: package de.eppleton.greetings is not visible
import de.eppleton.greetings.Greeter;
                  ^
  (package de.eppleton.greetings is declared in module de.eppleton.greetings, but module de.eppleton.hello does not read it)
1 error

Der Compiler beschwert sich, dass er die Klasse Greeter zwar kennt, dass sie aber für unsere HelloWorld-Klasse unsichtbar ist. Um dieses Problem zu beheben, müssen wir die module-info.java des Moduls de.eppleton.hello ändern und die Abhängigkeit vom Modul "de.eppleton.greetings" deklarieren:

src/de.eppleton.hello/module-info.java

Hier der Inhalt der Datei:

 module de.eppleton.hello { 
    requires de.eppleton.greetings;
}

Nun kompiliert das Projekt:

>javac --module-path modules -d modules/de.eppleton.hello src/de.eppleton.hello/de/eppleton/hello/HelloWorld.java src/de.eppleton.hello/module-info.java

und wir können es mit demselben Aufruf wie zuvor ausführen:

java --module-path modules -m de.eppleton.hello/de.eppleton.hello.HelloWorld 
Hello modular world!

Fehlender Export

Nun probieren wir noch aus was passiert, wenn man den Export vergisst. Wir ändern dazu die module-info des "greetings" Moduls:

src/de.eppleton.greetings/module-info.java

 module de.eppleton.greetings {
    exports de.eppleton.greetings;
 }

Nun kompilieren wir Alles erneut:

>javac -d modules/de.eppleton.greetings/ src/de.eppleton.greetings/module-info.java src/de.eppleton.greetings/de/eppleton/greetings/Greeter.java
>javac --module-path modules -d modules/de.eppleton.hello src/de.eppleton.hello/de/eppleton/hello/HelloWorld.java src/de.eppleton.hello/module-info.java
src/de.eppleton.hello/de/eppleton/hello/HelloWorld.java:2: error: package de.eppleton.greetings is not visible
import de.eppleton.greetings.Greeter;
                  ^
  (package de.eppleton.greetings is declared in module de.eppleton.greetings, which does not export it)
1 error

Und erneut erhalten wir eine aussagekräftige Fehlermeldung vom Compiler.

Zusammenfassung

Im ersten Teil der Serie haben wir uns angesehen, wie man ein Modul definiert. In diesem Teil haben wir eine Abhängigkeit von einem Modul auf das andere gesetzt und dabei gesehen, wie man Packages explizit exportieren muss, um sie in einem anderen Modul zu nutzen. Im nächsten Teil geht es darum, wie man das Modulsystem nutzt um ein Service Provider Interface (SPI) zu definieren, eine Implementierung dafür zur Verfügung zu stellen und diese Implementierung lose gekoppelt zu nutzen.

Besuchen Sie unsere Workshops zum Thema Java 9 um mehr über dieses und weitere neue Features von Java 9 zu erfahren: