modulitos
modulitos

Reputation: 15814

Eclipse PDE: Mimicking IResourceChangeEvents for IJavaProject creation between PDE and developer's workspace?

(NOTE - FINAL SOLUTION IS BELOW)

In my plug-in, I am trying to create an IJavaProject (using Eclipse JDT, code at the end) that creates a Java Project almost EXACTLY as if the IJavaProject were created by the developer (or whoever is using the plug-in). I am able to create the IJavaProject from my PDE, and it works fine, but I need to mimic the IResourceChangeEvents that arise from the project creation in my PDE to match the IResourceChangeEvents that arise from Java project creation in the developer's workspace.

I am measuring the 'IResourceChangeEvents' using my IResourceChangeListener (it uses a visitor, and should be correct - view the code here). When a Java Project is created in the developer's workspace, I am measuring the following IResourceChangeEvents:

CHANGE-ROOT (1 child)
    ADD-PROJECT (5 children)
        ADD-FILE ".classpath"
        ADD-FILE ".project"
        ADD-FOLDER ".settings" ADD-FILE ".prefs"
        ADD-FOLDER ".bin"
        ADD-FOLDER ".src"

And when I create an IJavaProject using Eclipse JDT in my PDE (code at the end), I measure these IResourceChangeEvents:

C-R 
    C-P 
        ADD-FILE ".project"
C-R 
    C-P "JavaProject"                       
C-R 
    C-P 
        CHANGE-FILE ".project"
C-R 
    C-P 
        ADD-FOLDER "bin"
C-R 
    C-P 
        C-F 
            ADD-FILE ".project"             
C-R 
    C-P 
        ADD-FILE ".classpath"
C-R 
    C-P 
        ADD-FOLDER "src"
C-R 
    C-P 
        CHANGED-FILE ".classpath"

Where C-R is CHANGED-ROOT, C-P is CHANGED-PROJECT and C-F is CHANGED-FILE.

Any suggestions on another way to create an IJavaProject?

Here is my IJavaProject creation code:

public static IJavaProject getJavaProject(IProject project) throws CoreException
{
    return getJavaProject(project, "src", "bin");
}


public static IJavaProject getJavaProject(IProject project, String sourceFolderPath,
                                           String binFolderPath) throws CoreException
{

    if (!project.exists())
        // This creates ADDED (.project)
        ResourceUtility.createProject(project);

    System.out.println("setting description nature id's.");
    IProjectDescription description = project.getDescription();
    description.setNatureIds(new String[] {JavaCore.NATURE_ID});
    System.out.println("setting project description.");
    // Creates CHANGED (JavaProject/.project)
    project.setDescription(description, null);
    System.out.println("Creating project.");

    // Does not do anything.
    IJavaProject javaProject = JavaCore.create(project);
    IFolder binFolder = project.getFolder(binFolderPath);
    // Creates ADDED (JavaProject/bin)
    binFolder.create(false, true, null);
    javaProject.setOutputLocation(binFolder.getFullPath(), null);
    System.out.println("Installing VM.");

    List<IClasspathEntry> entries = new ArrayList<>();
    IVMInstall vmInstall = JavaRuntime.getDefaultVMInstall();
    System.out.println("JDTUtil: vmInstall: " + vmInstall);
    LibraryLocation[] locations = JavaRuntime.getLibraryLocations(vmInstall);
    System.out.println("JDTUtil: lib locations: " + locations);
    // Creates ADDED (JavaProject/bin/.project) - ignored by RCL
    for (LibraryLocation element: locations)
    {
        entries.add(JavaCore.newLibraryEntry(element.getSystemLibraryPath(), null, null));
    }
    // add libs to project class path
    // Creates ADDED (JavaProject/.classpath)
    javaProject.setRawClasspath(entries.toArray(new IClasspathEntry[entries.size()]), null);
    //
    IFolder sourceFolder = project.getFolder(sourceFolderPath);
    // Creates ADDED (JavaProject/src)
    sourceFolder.create(false, true, null);

    IPackageFragmentRoot root = javaProject.getPackageFragmentRoot(sourceFolder);
    IClasspathEntry[] oldEntries = javaProject.getRawClasspath();
    IClasspathEntry[] newEntries = new IClasspathEntry[oldEntries.length + 1];
    System.arraycopy(oldEntries, 0, newEntries, 0, oldEntries.length);
    newEntries[oldEntries.length] = JavaCore.newSourceEntry(root.getPath());
    // Creates CHANGED (JavaProject/.classpath)
    javaProject.setRawClasspath(newEntries, null);
    return javaProject;
}

FINAL SOLUTION

As mentioned in the answer below, I batched the resource change events which causes Eclipse to build the IJavaProject much differently - and more efficiently - than without batching. As a result, my IJavaProject creation now matches Eclipse's internal resource tree representation for IJavaProject creation (WOOHOO!).

Here is my final solution:

public static IJavaProject getJavaProjectBatched(final IProject project, final String sourceFolderPath,
                                                 final String binFolderPath) throws CoreException
{
    IWorkspaceRunnable r = new IWorkspaceRunnable()
    {
         @Override public void run(@Nullable IProgressMonitor monitor) throws CoreException
        {
             if (!project.exists())
                 ResourceUtility.createProject(project);

             IProjectDescription description = project.getDescription();
             description.setNatureIds(new String[] {JavaCore.NATURE_ID});
             project.setDescription(description, null);

             IFolder binFolder = project.getFolder(binFolderPath);
             binFolder.create(false, true, null);
             final IFolder sourceFolder = project.getFolder(sourceFolderPath);
             sourceFolder.create(false, true, null);

             final IJavaProject javaProject = JavaCore.create(project);
             javaProject.setOutputLocation(binFolder.getFullPath(), null);

            IPackageFragmentRoot root = javaProject.getPackageFragmentRoot(sourceFolder);
            IClasspathEntry[] newEntries = new IClasspathEntry[1];
            newEntries[0] = JavaCore.newSourceEntry(root.getPath());
            javaProject.setRawClasspath(newEntries, null); 
        }
    };

    project.getWorkspace().run(r, null,IWorkspace.AVOID_UPDATE, null);
    @SuppressWarnings("null") @NonNull IJavaProject javaProject = JavaCore.create(project);
    return javaProject;
}

Here is the new resource tree, which matches the resource tree that I needed above (excluding the .settings folder - just an artifact from manual creation).

CHANGE-ROOT (1 child)
    ADD-PROJECT (4 children)
        ADD-FILE ".classpath"
        ADD-FILE ".project"
        ADD-FOLDER ".bin"
        ADD-FOLDER ".src"

Upvotes: 1

Views: 96

Answers (1)

Chris Gerken
Chris Gerken

Reputation: 16392

Try these two things:

  • Use an implementation of IWorkspaceRunnable to batch all of the resource changes into a single transaction. That should make the changes look much more like the create project resource delta.

  • Make sure that the project is deleted from disk before running your code. It looks like you deleted it from the workspace but not the file system.

Upvotes: 1

Related Questions