[Eclipse] Ermitteln von Abhängigkeiten

qwertz_

Grünschnabel
Hallo,

ich schreibe gerade an einem Plugin für Eclipse, welches Quellcode auf verschiedene Art und Weisen analysieren kann.
Hierfür ist es unter anderem auch notwendig, dass ich Abhängigkeiten zwischen Artefakten (also Klassen, Methoden, Pakete) ermittle.

Mit Hilfe des JDT-ASTParser ist dies ja prinzipiell möglich. Hat hier jemand eventuell schon damit so seine Erfahrungen gemacht und kann mir ein paar Fragen dazu beantworten?

Ich habe zur Zeit noch viele Probleme mit den sogenannten "Bindings", welche der Parser generieren kann. Diese spiegeln ja praktisch schon die Abhängigkeiten zwischen Artefakten wider, können aber leider nur von Eclipse-Projekten (und nicht beliebigen Quellcode) gebildet werden.

Eventuell hat ja jemand eine Idee, wie ich fremden Quellcode als ein Eclipse-Projekt "reinladen" kann... oder eventuell hat ja jemand eine ganz andere Idee, wie ich (eventuell auch ohne JDT) die Abhängigkeiten ermittle.

Danke.
MfG
qwertz_
 
Hallo!
ich schreibe gerade an einem Plugin für Eclipse, welches Quellcode auf verschiedene Art und Weisen analysieren kann.
Hierfür ist es unter anderem auch notwendig, dass ich Abhängigkeiten zwischen Artefakten (also Klassen, Methoden, Pakete) ermittle.
Du willst also verschiedene Quellcode Metriken erheben und Abhängigkeiten Visualisieren...

Mit Hilfe des JDT-ASTParser ist dies ja prinzipiell möglich. Hat hier jemand eventuell schon damit so seine Erfahrungen gemacht und kann mir ein paar Fragen dazu beantworten?
Also ich denke auf den JDT-AST musst du nur dann zurückgreifen wenn du wirklich innerhalb eines Types irgendwelche
Metriken erheben willst (größte Anzahl an Parametern, anzahl an Attributen etc...) Wenn du Highlevel auf das Code-"Model" zugreifen willst solltest du das "JavaModel" des "JavaProjects" analysieren. Weiterehin wäre es IMHO, beispielsweise zum finden der Abhängigkeiten, eine Möglichkeit die interne Java-spezifische Suche von Eclipse (über API) zu verwenden.
-> findReferences etc...

Ich habe zur Zeit noch viele Probleme mit den sogenannten "Bindings", welche der Parser generieren kann. Diese spiegeln ja praktisch schon die Abhängigkeiten zwischen Artefakten wider, können aber leider nur von Eclipse-Projekten (und nicht beliebigen Quellcode) gebildet werden.
Wie schon gesagt, an deiner Stelle würde ich mir mal das JavaModel-Abstraktion des JavaProjects mal genauer anschauen.

Eventuell hat ja jemand eine Idee, wie ich fremden Quellcode als ein Eclipse-Projekt "reinladen" kann... oder eventuell hat ja jemand eine ganz andere Idee, wie ich (eventuell auch ohne JDT) die Abhängigkeiten ermittle.
Ich bau mal ein kleines Beispiel dazu...

Btw. du könntest für deine Analysen auch ein ThridParty Tool (und somit auch dessen Objekt-Modell) verwenden. Beispiele hierfür wären JDepend und PMD...

Gruß Tom
 
Hallo!

Hab mal ein Beispiel für den Zugriff auf JavaProjekte im Workspace gebastelt...
Java:
/**
 * 
 */
package de.tutorials.javaplugin;

import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.ui.IWorkbenchWindow;

/**
 * @author Thomas.Darimont
 * 
 */
public class JavaProjectAccessExample {

    public static void demonstrate(IWorkbenchWindow window) {
        IProject[] projects = ResourcesPlugin.getWorkspace().getRoot()
                .getProjects();

        for (int i = 0; i < projects.length; i++) {
            IProject project = projects[i];
            System.out.println("Found Project: " + project);

            IJavaProject javaProject = JavaCore.create(project);
            listJavaFilesFor(javaProject);
        }
    }

    private static void listJavaFilesFor(IJavaProject javaProject) {
        try {
            IPackageFragment[] packageFragments = javaProject
                    .getPackageFragments();
            for (int i = 0; i < packageFragments.length; i++) {
                IPackageFragment packageFragment = packageFragments[i];
                if (packageFragment.containsJavaResources()) {
                    IJavaElement[] packageFragmentChildren = packageFragment.getChildren();
                    for (int j = 0; j < packageFragmentChildren.length; j++) {
                        IJavaElement javaElement = packageFragmentChildren[j];
                        System.out.print(javaElement);
                        System.out.print(" Contains: ");
                        printNestedTypesFor((ICompilationUnit) javaElement);
                        System.out.println();
                    }
                }
            }
        } catch (JavaModelException e) {
            e.printStackTrace();
        }
    }

    private static void printNestedTypesFor(ICompilationUnit compilationUnit) {
        try {
            IType[] types = compilationUnit.getAllTypes();
            for (int i = 0; i < types.length; i++) {
                IType type = types[i];
                System.out.print(type.getFullyQualifiedName());
                if (i + 1 != types.length) {
                    System.out.print(", ");
                }
            }
        } catch (JavaModelException e) {
            e.printStackTrace();
        }
    }

}

Ausgabe:
Code:
Food.java (not open) [in de.tutorials [in src [in de.tutorials.training]]] Contains: de.tutorials.Food, de.tutorials.Food$Soup, de.tutorials.Food$Potato
JDBCMetaDataExample.java (not open) [in de.tutorials [in src [in de.tutorials.training]]] Contains: de.tutorials.JDBCMetaDataExample
ConstructorMagic.java (not open) [in de.tutorials [in src [in de.tutorials.training]]] Contains: de.tutorials.ConstructorMagic, de.tutorials.ConstructorMagic$Foo, de.tutorials.ConstructorMagic$Bar
SimpleExample.java (not open) [in de.tutorials [in src [in de.tutorials.training]]] Contains: de.tutorials.SimpleExample, de.tutorials.SimpleExample$Base, de.tutorials.SimpleExample$Derived
BlinkingApplet.java (not open) [in de.tutorials [in src [in de.tutorials.training]]] Contains: de.tutorials.BlinkingApplet
Person.java (not open) [in de.tutorials [in src [in de.tutorials.training]]] Contains: de.tutorials.Person
SWTExample.java (not open) [in de.tutorials [in src [in de.tutorials.training]]] Contains: de.tutorials.SWTExample
MultiLineButtonExample.java (not open) [in de.tutorials [in src [in de.tutorials.training]]] Contains: de.tutorials.MultiLineButtonExample
DB4oClient.java (not open) [in de.tutorials [in src [in de.tutorials.training]]] Contains: de.tutorials.DB4oClient
SWTProgramStarterExample.java (not open) [in de.tutorials [in src [in de.tutorials.training]]] Contains: de.tutorials.SWTProgramStarterExample
ConstructorExample.java (not open) [in de.tutorials [in src [in de.tutorials.training]]] Contains: de.tutorials.ConstructorExample, de.tutorials.ConstructorExample$Base, de.tutorials.ConstructorExample$Impl
ConcurrentHashMapExample.java (not open) [in de.tutorials [in src [in de.tutorials.training]]] Contains: de.tutorials.ConcurrentHashMapExample
LoadLibraryExample.java (not open) [in de.tutorials [in src [in de.tutorials.training]]] Contains: de.tutorials.LoadLibraryExample
FutureTaskExample.java (not open) [in de.tutorials [in src [in de.tutorials.training]]] Contains: de.tutorials.FutureTaskExample, de.tutorials.FutureTaskExample$FunctionGenerator, de.tutorials.FutureTaskExample$Function, de.tutorials.FutureTaskExample$FunctionEvaluator
BinaryTreeExample.java (not open) [in de.tutorials [in src [in de.tutorials.training]]] Contains: de.tutorials.BinaryTreeExample, de.tutorials.BinaryTreeExample$TreeNode
CrazyStrings.java (not open) [in de.tutorials [in src [in de.tutorials.training]]] Contains: de.tutorials.CrazyStrings
CompletionExample.java (not open) [in de.tutorials [in src [in de.tutorials.training]]] Contains: de.tutorials.CompletionExample
TreeNode.java (not open) [in de.tutorials [in src [in de.tutorials.training]]] Contains: de.tutorials.TreeNode
EnumExample.java (not open) [in de.tutorials [in src [in de.tutorials.training]]] Contains: de.tutorials.EnumExample
Generics.java (not open) [in de.tutorials [in src [in de.tutorials.training]]] Contains: de.tutorials.Generics
PrimeExample.java (not open) [in de.tutorials [in src [in de.tutorials.training]]] Contains: de.tutorials.PrimeExample
XMLExample.java (not open) [in de.tutorials [in src [in de.tutorials.training]]] Contains: de.tutorials.XMLExample, de.tutorials.XMLExample$Dict
DB4oServer.java (not open) [in de.tutorials [in src [in de.tutorials.training]]] Contains: de.tutorials.DB4oServer
Parent.java (not open) [in de.tutorials [in src [in de.tutorials.training]]] Contains: de.tutorials.Parent
SplashScreenExample.java (not open) [in de.tutorials [in src [in de.tutorials.training]]] Contains: de.tutorials.SplashScreenExample, de.tutorials.SplashScreenExample$SplashScreen
Color.java (not open) [in de.tutorials [in src [in de.tutorials.training]]] Contains: de.tutorials.Color, de.tutorials.Color$IColorHandler, de.tutorials.Color$DefaultColorHandler
GenericsExample.java (not open) [in de.tutorials [in src [in de.tutorials.training]]] Contains: de.tutorials.GenericsExample
ConnectionDesc.class (not open) [in com.sun.jndi.ldap.pool [in C:\Programme\Java\jdk1.6.0\jre\lib\rt.jar]] Contains:

Gruß Tom
 

Anhänge

Hallo,

vielen Dank für die ausführliche Antwort und das Beispiel.
Eventuell sollte ich meine Aufgabe mal etwas ausführlicher beschreiben:

Es soll ein Eclipse-Plugin entwickelt werden, welches sozusagen den Entwicklungsprozess eines Softwareprojektes visualisieren kann. Hierfür kann der Benutzer einen Subversion-Server angeben sowie eine Spanne von Revisionen.
Das Plugin lädt dann diese Revisionen und analysiert sie. Es werden zum Beispiel Daten wie "Lines of Code", "Comment Lines of Code" oder auch Anzahl an Vorkommen verschiedener Syntaxbaumknotentypen gesammelt.
Es soll drei Visualisierungsformen geben und darunter auch eine, welche die Beziehungen zwischen allen Artefakten anzeigen kann. Ob es sich dabei um eine Vererbungs oder "Benutzt"-Beziehung handelt, spielt für die Visualisierung keine Rolle. Es wird einfach eine Linie zwischen den Artefakten eingezeichnet.

Dadurch dass der Benutzer einen beliebigen Subversion-Server angeben kann, ist nicht sichergestellt, dass dort auch wirklich ein Eclipse-Projekt liegt.
Selbst wenn dies so sein sollte, so müsste ich es immernoch nach dem Runterladen irgendwie in Eclipse reinladen.
D.h. dieses Plugin weicht von den herkömmlichen Plugins ab, welche ja mit Eclipse-Projekten arbeiten, die der Benutzer selber geöffnet hat.

Ich werde mir mal das von Dir genannte "JavaModel" genauer anschauen, eventuell hilft mir ja das ein wenig weiter.
 
Zurück