Java Jigsaw - Modul Zugriffsrechte

Servus,
bin neu hier & weiß evtl. noch nicht wie ich die Frage zu 100% korrekt stelle. Ich hab mich jetzt in Jigsaw versucht einzuarbeiten & die Grundzüge (glaube ich) verstanden. Bin jedoch auf ein Problem gestoßen.
Die Frage ist: Wie können einzelne Module über mehrere (Import) Schichten kommunizieren?
Um mal konkret zu werden: Ich habe 2 Module „Bar“ & „Drink“. Bar braucht Drink. Ich möchte nun außerdem noch in BEIDEN Modulen (mittels JUnit) Testen. Logischer weise, brauchen dann beide Module Zugriff auf das (automatische) JUnit Modul. Ich fange also mit „Drink“ an & füge dort JUnit hinzu. Hier dann der simple Code für „Drink“:

module-info.java

module drink {

exports drink;

requires junit;
requires java.hamcrest;

}

Drink.java

package drink;

public class Drink {

private int milliliters = 250;

public int getMilliliters() {
	return this.milliliters;
}

public void setMilliliters(int milliliters) {
	this.milliliters=milliliters;
}

}

DrinkTest.java

package drink.test;

import static org.junit.Assert.assertEquals;

import org.junit.Test;

import drink.Drink;

public class DrinkTest {

@Test
public void testDrink() {
	Drink testDrink = new Drink();
	assertEquals(testDrink.getMilliliters(), 250);
}

}

Das funktioniert auch alles wie es soll. Nun packe ich den ganzen Kram als JAR zusammen & füge es dann dem anderen Modul hinzu. Für das Drink Modul ist das auch absolut Problemlos. Nun will ich aber eben auch ein paar Tests für „Bar“ schreiben und brauche dafür JUnit. Dieses kann aber nicht mehr gefunden werden:


Somit nun die konkrete Frage: Wie bekomm ich JUnit in „Bar“ sichtbar?

Ich tippe Mal drauf genauso wie du es in DRINK gelöst hast. Du musst die jar nochmal angeben.

Könnte sein, dass du junit auch reexportieren könntest (was auf mich aber unsauber wirken würde).

Abgesehen davon kann ich dir allerdings nur davon abraten Jigsaw zu verwenden. Denn es ist nicht kompatibel mit maven. Hatte versucht das für unsere Microservices in der Firma zu nutzen aber ist halt nicht möglich. Entweder es war nie für den Endanwender gedacht oder Oracle hat hart scheiße gebaut.

Hmm…, was meinst du mit JAR angeben? Die JAR ist im Module-Path von „BAR“. Hab ich da was verpasst bei Jigsaw? Dachte eigentlich, dass ich nun Zugriff auf alles habe, was ich exportiert habe?
properties

Das hast du richtig erfasst. Aber wenn du dir dein module anschaust, dann exportierst du „nur“ das bar-package. Die anderen (drink, junit, hamcrest) sind dort nur als Dependencies angegeben, werden aber nicht automatisch nicht exportiert.

Also ja, du müsstest die jar auch im module-path von bar zur Verfügung stellen.

Ach soooo…, ok ich glaub jetzt versteh ich was du meinst. Du willst, dass ich die JUnit JAR einfach nochmal mit mit dem neuen Modul verknüpfe?!? Ja gut, dann hab ich’s halt doppelt. Es hat ja dann überhaupt keinen Sinn JUnit in die Drink-JAR zu packen, wenn ich eh nicht drauf zugreifen kann.
Das ist ein Möglichkeit, aber für mich nicht zu gebrauchen. Das Problem was ich hier in diesen Democode habe ist äquivalent zum echten Problem. Es geht hier um ein Softwarepraktikum für eine Hochschule. Die Studenten sollen bei einem vorgefertigtem Framework Code ergänzen (auch ein paar eigene Tests schreiben). Da es sich um relative Anfänger handelt, will ich es für die so einfach wie nur irgend möglich machen. Ich will also zum Schluß genau 1 JAR haben, die die importieren & dann mit ihrem Code erweitern. In dieser einen JAR soll also alles was sie brauchen drin sein (eben auh JUnit). Dadurch können wir auch bzgl. Korrekturen viel systematischer vorgehen, weil es bei ca. 120 Studenten dann nicht unendlich viele Versionskombinationen von den Biblitheken gibt, sondern jeder mit dem selben Code arbeiten muss.

Um ehrlich zu sein würde ich da noch sehr viel mehr Abstand zu Jigsaw nehmen. Die Studenten beschäftigen sich sonst mit etwas, was sie vermutlich niemals brauchen werden.

Zudem würde auch das packaging an sich keinen Sinn machen. Man liefert den Testcode nicht mit der Anwendung aus.

Von daher würde ich wieder auf meine Ursprüngliche Empfehlung zurückkommen: nimm maven.

Genau das kannst du mit Maven erreichen. Die Studenten brauchen dann nur die pom.xml - das wars. Darin gibst du dann an welche Abhängigkeiten (junit, hamcrest) du haben möchtest. Die richtigen jars werden dann automatisch heruntergeladen und ins Projekt eingebunden.

Die Entscheidung was, wann, wie genutzt wird ist schon lange gefallen. Mir sind die Vorzüge von Maven durchaus bekannt. Dennoch ist das völlig irrellevant. Ich habe leider exakt garnix zu entscheiden. Ich bin das letzte Licht an einer laaaaangen Lichterkette von Entscheidungen & darf „nur“ programmieren.
Die Entscheidung war: Wir wollen 1 JAR die wir an die Studenten verteilen können. Fertig.
Von daher hab ich da überhaupt keine Wahl.
Trotzdem danke.

Geht es nur um die jar oder muss es unbedingt jigsaw sein? Oder wäre eine fatjar übern classpath auch ok?

Nein, Jigsaw wäre nicht notwendig. Prinzipiell könnte ich also darauf verzichten. ABER, da das Framework auch internen Testcode mit ausliefert (damit sich die Studenten bzw. ihre Implementierung zu jeder Zeit selber testen können), wäre dieses Modulsystem ideal. Es existiert, dann natürlich im Framework eine Musterlösung. Diese ist dann prinzipiell aufrufbar. Wir haben zwar ein paar interne Tests die dass testen, ABER die können ausgetrickst werden. Somit wäre hier Jigsaw tatsächlich eine sehr gute Variante. Damit könnten wir die ganzen Tests bzgl. Musterlösung wieder raus schmeißen, weil der Compiler per se sagen würde, dass er keinen Zugriff auf die Musterlösung hat.

Warum existiert im Framework eine Musterlösung - die nicht aufrufbar sein soll.

Zum einen könnte man mittels decompiler da dran kommen, zum anderen: warum Sachen ausliefern, die man nicht ausliefern möchte?

Vielleicht verstehe ich dich auch falsch. Aber sollte es nicht vollkommen ausreichen, wenn die Studenten eine fatjar mit folgendem inhalt bekommen:

  • Dependencies (junit, hamcrest, …)
  • Vorgefertigte Tests
  • Ggf. Hilfsklassen etc…

Also wenn du mich fragst, dann ist das kein Einsatzgebiet von Modulen.

Doch genau für sowas wurde das Modulsystem eingeführt (unter anderem). Man will sehr genau steuern, wer wann welchen Zugriff bekommt.
Im alten Java (< 9) funktioniert Zugriffskontrolle nur innerhalb eines Packages. Sobald du aber mehrere Packages hast, welche untereinander kommunizieren sollen hast du bzgl. Zugriffskontrolle in Java verloren. Zumindestens ohne Jigsaw. Denn dann MUSST du deine Methoden/Attribute public setzen & damit sind sie von jeder beliebigen stelle im Programm erreichbar. Mit Jigsaw, kann man das wesentlich feiner steuern.
Und was den Code der Musterlösung angeht, wie schon oben beschrieben: Die Studenten sollen sich zu jeder Zeit selber testen können. Dazu wird eine Musterlösung gegen deren Code getestet. Wenn die Ergebnisse identisch sind, dann funktioniert deren Code. Wenn nicht, dann nicht.