# Module Eclipse Java 9



## LeNkUeP (29. Jan 2018)

Ich muss zur Zeit mit dem neuen Feature der Modularisierung in Eclipse arbeiten und soll vorhandenen Code "modularisieren" :/

Dieser ganze Modularisierungsprozess erwies sich derweil als ziemlich kompliziert und im Internet gibt es zu speziellen Problemen kaum Hilfe (speziell in Eclipse).
Bis jetzt habe ich mir die Grundlagen der Modularisierung schon aneignen können, jedoch besteht folgendes Problem:

Ich habe zwei Projekte: "module4711" und "module4712" welche jeweils ein gleichnamiges Modul enthalten.
In beiden Projekten gibt es das Package "com.itsg.deuv.kernpruefung" (genau das Gleiche) und in beiden Projekten gibt es in diesem Package eine Klasse "a"... also gleiches Package und doppelte Klasse "a".
Diese Klasse a hat jedoch in beiden Projekten eine unterscheidbare Methode getInfo()...die eine gibt ganz einfach "4711" aus und die andere "4712".
Die Module "exportieren" beide jeweils das Package!

Dann gibt es noch die Projekte "XYVersion4711" und "XYVersion4712".
Diese besitzen jeweils ein, dem Projektnamen entsprechendes, Package und in diesem Package gibt es die Klassen v4711 (XYVersion4711) und v4712 (XYVersion4712), welche beide eine Methode besitzen, welche a.getInfo() aufrufen, also die in den Modulen genannte Methode welche sich trotz gleichen Packages unterscheiden soll!
Damit die Klassen überhaut zugreifen dürfen, müssen ja auch diese Projekte ein Modul enthalten was die oberen Module "required".
Also habe ich die Module "module4711_2" und "module4712_2", welche logischerweise die oberen Module "requiren", erstellt.
Auch diese Module "exportieren" jeweils das Package im jeweiligen Projekt!
Über den Modulpfad ist Projekt "module4711_2" logischerweise mit "module4711" verknüpft, genauso bei "module4712_2" und "module4712", da die Module sonst nicht gefunden werden würden!

Zu guter Letzt gibt es noch das Projekt "Main Project", welches über ein Modul "mainProject" Zugriff auf die Module von XYVersion(...) erhält.
Auch hier wurde der Modulpfad verwendet.
In einer Main-Methode soll jetzt v4711.getInfo() und v4712.getInfo() ausgeführt werden, und das erwartete Ergebnis soll eigentlich einmal "4711" und einmal "4712", quasi dass über die vorhandenen Abhängigkeiten zwischen den gleichen Klassen "a" die verschiedenen Inhalte ausgeführt werden.
Leider wird ein Fehler ausgegeben:

```
Error occurred during initialization of boot layer
java.lang.LayerInstantiationException: Package com.itsg.deuv.kernpruefung in both module module4712 and module module4711
```

In jeder Klasse wurden logischerweise auch die benötigten Importe gemacht und es gibt an sich keinen Fehler...

Wenn ich die gleichnamigen Packages unterscheidbar mache, sprich einen Namen änder dann funktioniert es gut.
Problem liegt also darin dass das Package zweimal verwendet wird...

Habt ihr eine Idee wie ich es schaffe bei gleichem Package und gleichnamiger Klasse mit verschiedenen Inhalten andere Ausgaben erziele?
Im Folgenden werde ich auch noch ein paar Bilder hochladen^^

Danke im Vorraus

PS: Habe Java 9 installiert, also Compiler = 9 usw.


----------



## mrBrown (29. Jan 2018)

Afaik ist‘s nicht möglich, verschiedene Versionen einer Klasse zu laden, zumindest nicht ohne rumbasteln mir Classloadern

(Dein Problem ist aber auch schon extrem konstruiert, das ist doch kein echter vorhandener Code?)


----------



## LeNkUeP (29. Jan 2018)

Nene das war jetzt speziell um das zu testen 
Den Eindruck habe ich mittlerweile auch...hättest du denn eine Idee zum Punkt: "Mit Classloadern rumbasteln"?
Aber danke schonmal.


----------



## mrBrown (29. Jan 2018)

LeNkUeP hat gesagt.:


> hättest du denn eine Idee zum Punkt: "Mit Classloadern rumbasteln"?


Zumindest keine in diesem Fall anwendbare.


So eine Struktur sollte auch generell einfach vermieden werden


----------



## LeNkUeP (29. Jan 2018)

Danke trotzdem


----------



## JuKu (7. Feb 2018)

Wie @mrBrown sagte, solltest du solche Strukturen definitiv vermeiden. Doppelte Packages & Klassen sollte es so oder so nicht geben, sonst stimmt etwas mit deiner Software Architektur / Software Design nicht.
Ausnahme: Du supportest mehrere Versionen, dies unterstützt Jigsaw (so nennt sich das neue Modulsystem unter Java 9) aber derzeit noch nicht (soll evtl. im März mit Java 10 kommen), dann kannst du aber trotzdem immer nur eine von beiden Varianten einbinden.


----------



## mrBrown (7. Feb 2018)

JuKu hat gesagt.:


> soll evtl. im März mit Java 10 kommen


Mit 10 wird's nicht kommen: openjdk.java.net/projects/jdk/10/

Für 11 ist's auch noch nicht angedacht.


----------



## JuKu (7. Feb 2018)

Ah ja, die haben das wieder rausgenommen bzw. gar nicht auf Targeted gesetzt, weil es viele Unstimmigkeiten in der Expertengruppe war.
Danke!
Daran hatte ich jetzt ehrlich gesagt gar nicht mehr gedacht. Versionierung der Module war schon bei Java 9 eine heiß diskutierte Sache und bis jetzt gibt es noch keine Lösung, die allen Java EC Mitgliedern gefällt.


----------



## JuKu (7. Feb 2018)

Leider war es nicht möglich beim Editieren von Beiträgen Bilder hochzuladen, deshalb hier ein neuer.
Hier der entscheidende Absatz des Java Expertengruppen-Meetings:


----------



## LeNkUeP (14. Feb 2018)

Danke erstmal für die Antworten
Habe jetzt die Modularisierung erstmal beiseite gelegt und mit URLClassLoader gearbeitet, mit welchem am Ende tatsächlich das gewünschte Ergebnis herauskam.
Durch verschiedene Jars und einen Umweg über ein Interface hats dann doch noch geklappt...Werde den Code auch noch mal hochladen für alle die es interessiert.


----------



## LeNkUeP (14. Feb 2018)

Hier der Code der Main Klasse (oberste Ebene):

```
package MainProject;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;

public class versionsSwitcher {

    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, IOException, IllegalArgumentException, InvocationTargetException {
        versionsSwitcher switcher = new versionsSwitcher();
        switcher.test();
    }
   
    public void test()
            throws ClassNotFoundException, InstantiationException, IllegalAccessException, IOException, IllegalArgumentException, InvocationTargetException {
        URL[] urls = new URL[2];
        urls[0] = new URL("file:C:\\Users\\lku\\Desktop\\ModulesAndJars\\kernpruefung4711.jar");
        urls[1] = new URL("file:C:\\Users\\lku\\Desktop\\ModulesAndJars\\v4711Test.jar");
        URLClassLoader urlClassLoader = new URLClassLoader(urls);
       
        Class<?> c1 = Class.forName("XYVersion4711.v4711", false, urlClassLoader);
       
        Method[] methods = c1.getMethods();
        Method method = methods[0];
        method.invoke(c1.newInstance());

        urlClassLoader.close();

        urls = new URL[2];
        urls[0] = new URL("file:C:\\Users\\lku\\Desktop\\ModulesAndJars\\kernpruefung4712.jar");
        urls[1] = new URL("file:C:\\Users\\lku\\Desktop\\ModulesAndJars\\v4712Test.jar");
        urlClassLoader = new URLClassLoader(urls);
        c1 = Class.forName("XYVersion4712.v4712", false, urlClassLoader);

        Method[] methods2 = c1.getMethods();
        Method method2 = methods2[0];
        method2.invoke(c1.newInstance());
       
        urlClassLoader.close();
    }

}
```

Hier der Code zu der zweiten Ebene (XYVersion4711 und -4712):

```
package XYVersion4711;

import com.itsg.deuv.kernpruefung.a;

public class v4711 {
   
    public void teste() {
        a klasse = new a();
        klasse.getInfo();
    }

}
```

--> Der Code von v4712 ist denkbar ähnlich^^

Hier der Code der untersten Ebene (doppelte Klasse a):

```
package com.itsg.deuv.kernpruefung;

public class a {
   
    public void getInfo() {
        System.out.println("4711");
    }
   
}
```

--> Auch hier ist der leichte Unterschied zu 4712 erkennbar (steht alles oben beschrieben)

Zu den Beziehungen: Nur die 2te Ebene (XYVersion4711.v4711 und (...)) ist über den Klassenpfad mit der jeweiligen Version von a verbunden, sonst nichts.
Denn wenn man in der Main Klasse (versionSwitcher) einen Klassenpfad zur 2ten Ebene angibt, ist dieser final und es wird unmöglich die beiden Versionen von a zu unterscheiden.
Daher die oben sichtbaren URLs...die gehören zu 4 Jar Dateien welche ich zu der 2ten ebene und zur 1ten Ebene erstellt (exportet) habe. Hier muss der Classloader die nur leicht unterschiedlichen Jars laden und kann so unterscheiden.

Dieses method.invoke (Reflection) kann man auch durch ein Interface umgehen, welches dafür sorgt dass man ein explizites Objekt erstellen kann...den Code kann ich auf Anfrage auch mal posten...


----------



## mrBrown (14. Feb 2018)

Ich hoffe von ganzem Herzen, dass die Problembeschreibung und dieser Code niemals was mit Produktivcode zu tun haben werden


----------



## LeNkUeP (20. Feb 2018)

Hoffen wir es mal ^^
Aber trotzdem mal ganz interessant wie man das machen müsste


----------

