Reputation: 15814
(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
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