Automatisches Einfügen eines Classpath Containers

Aus Eclipse
Version vom 15. Juli 2010, 15:07 Uhr von Thies (Diskussion | Beiträge)

(Unterschied) ← Nächstältere Version | Aktuelle Version (Unterschied) | Nächstjüngere Version → (Unterschied)
Wechseln zu: Navigation, Suche

Wie schon in Beispiel MUT Classpath Container erwähnt, wird ein Classpath Container über den Erweiterungspunkt org.eclipse.jdt.core.classpathContainerInitializer initialisiert. In einer Klasse, welche von der Klasse org.eclipse.jdt.core.ClasspathContainerInitializer abgeleitet sein muß, wird die Methode initialize(IPath path, IJavaProject project) implementiert.
Diese Methode hat zwei Aufgaben:

  • Sie erzeugt eine Instanz einer Klasse, welche das Interface IClasspathContainer implementiert. Dieser Classpath Container enthält eine Menge von Classpath Entries, z.B. JAR-Bibliothekeken (Library Classpath Entries), Classpath-Variablen (Variable Classpath Entries) oder Projekte (Required Project Classpath Entries).
  • Sie bindet den neuen Classpath Container an das übergebene Java-Projekt:
 JavaCore.setClasspathContainer( path,
      new IJavaProject[] { project },
      new IClasspathContainer[] { createdClasspathContainer },
      null );

Soll ein Classpath Container z.B. im Rahmen eines Refactorings einem Java-Projekt programmgesteuert hinzugefügt werden, kann man genauso vorgehen wie Eclipse beim manuellen Hinzufügen des Containers via „Add Library“:

  • Zuerst wird via JavaCore ein neuer Classpath Container Entry erzeugt, wobei nur die ID des Containers (der Container Path) angegeben wird.
  • Anschließend besorgt man sich via JavaCore den Initializer für den Classpath Container und ruft die Methode initialize() für das gegebene Projekt auf, wodurch der eigentliche Container erzeugt und an das Projekt gebunden wird (s.o.).
  • Schließlich wird der Classpath des Java-Projektes um den neuen IClasspath-Entry erweitert.

Das folgende Codebeispiel zeigt die drei Schritte:

 // Create new Classpath Container Entry
 containerEntry = JavaCore.newContainerEntry(new Path("org.example.container"));

 // Initialize Classpath Container
 ClasspathContainerInitializer containerInit = 
    JavaCore.getClasspathContainerInitializer("org.example.container");
 containerInit.initialize(new Path("org.example.container"), project);

 // Set Classpath of Java Project
 List<IClasspathEntry> projectClassPath = new ArrayList<IClasspathEntry>(
    Arrays.asList(project.getRawClasspath()));
 projectClassPath.add(containerEntry);
 project.setRawClasspath(projectClassPath.toArray(new IClasspathEntry[projectClassPath.size()]), null);

Classpath Container bieten eine elegante Möglichkeit, mehrere Classpath Entries zusammenzufassen. Sie haben allerdings einen Nachteil: Wenn Eclipse neu gestartet wird, wird für jedes Projekt im Workspace der Classpath neu aufgelöst. Dabei wird für jeden Classpath Container Entry der entsprechende Initializer aufgerufen, der das eigentliche Container-Objekt neu erzeugt und an das Projekt bindet! Offensichtlich werden diese Objekte nicht persistent gespeichert.

Dies bedeutet, daß man nicht sicher sagen kann, ob ein dem Projekt hinzugefügter Classpath Container nach dem Neustart von Eclipse noch denselben Inhalt hat, denn dieser hängt vom Code des Plugins ab, welches den entsprechenden Container Initializer zur Verfügung stellt. Im schlimmsten Fall kann der Container-Inhalt von den Voreinstellungen des Plugins und auch vom Vorhandensein bzw. Nicht-Vorhandensein anderer Plugins abhängig sein.

Wenn man den Classpath eines Projektes so erweitern will, daß die hinzugefügten Classpath Entries garantiert konstant bleiben, kann man statt eines Containers die nötigen JAR-Bibliotheken direkt als Library Classpath Entries einfügen, z.B.:

 List<IClasspathEntry> projectClassPath = new ArrayList<IClasspathEntry>(
     Arrays.asList(project.getRawClasspath()));
 projectClassPath.add(
    JavaCore.newLibraryEntry(
       Path.fromOSString("C:\\dir\\lib.jar"),
       null,
       null)
 );
 project.setRawClasspath(projectClassPath.toArray(new IClasspathEntry[projectClassPath.size()]), null);