Bug 124290

Summary: AbstractImageBuilder writeClassFileBytes creates resources before calling setDerived
Product: [Eclipse Project] JDT Reporter: Jeremy Sheeley <jeremy>
Component: CoreAssignee: Kent Johnson <kent_johnson>
Status: VERIFIED FIXED QA Contact:
Severity: normal    
Priority: P3 CC: jeremy, john.arthorne
Version: 3.1   
Target Milestone: 3.2 M5   
Hardware: PC   
OS: Windows XP   
Whiteboard:
Bug Depends on: 124322    
Bug Blocks:    

Description Jeremy Sheeley CLA 2006-01-18 09:21:03 EST
In the else clause of writeClassFileBytes:
// Default implementation just writes out the bytes for the new class file...
		if (JavaBuilder.DEBUG)
			System.out.println("Writing new class file " + file.getName());//$NON-NLS-1$
		file.create(new ByteArrayInputStream(bytes), IResource.FORCE, null);
		file.setDerived(true);

create calls Workspace.endOperation(), which will sometimes (if the build takes long enough) call broadcastPostChange().  This means that a IResourceChangeListener listening to IResourceChangeEvent.POST_CHANGE events will have find one class file resource which is not marked derived.  This means that team providers who are listening to POST_CHANGE events to add non-derived resources, will accidentally add class files.

I propose that it should call setDerived(true) before calling create().
Comment 1 Jeremy Sheeley CLA 2006-01-18 09:22:29 EST
Also, any advice on a workaround for 3.0 and 3.1 would be appreciated.
Comment 2 Jerome Lanneluc CLA 2006-01-18 09:29:54 EST
I believe that calling setDerived(boolean) on an IFile that doesn't yet exist will throw a CoreException.
We might need a new API from Platform/Resources.
Comment 3 Kent Johnson CLA 2006-01-18 10:12:09 EST
John: are post change events postponed until the build finishes?
Comment 4 Philipe Mulet CLA 2006-01-18 11:29:53 EST
We would need an atomic derived file creation. Maybe we could nest both actions into a batch operation, but it feels overkill.
Comment 5 John Arthorne CLA 2006-01-18 11:34:01 EST
I agree you would need new API from core.  I will do this.
Comment 6 John Arthorne CLA 2006-01-18 15:52:36 EST
I have added new API from core.  You can now replace those two lines with:

file.create(new ByteArrayInputStream(bytes), IResource.FORCE|IResource.DERIVED, null);
Comment 7 Jeremy Sheeley CLA 2006-01-19 10:34:57 EST
Workaround for those who are developing 3.0 and 3.1 plugins and encounter this bug:

In your class that implements IResourceChangeListener, save all of the resources that are not marked derived in the delta.  Create a new Job and call

myJob.setRule(ResourcesPlugin.getWorkspace().getRuleFactory().modifyRule(ResourcesPlugin.getWorkspace().getRoot()));

In the Job's run method, you can loop over the resources re-checking to see if they are still derived.  The rule will prevent the job from running until after the build is finished.

Comment 8 Kent Johnson CLA 2006-01-20 11:36:33 EST
John, do we also need a new API for:

folder.create(true, true, null);
folder.setDerived(true);

and

file.setContents(new ByteArrayInputStream(bytes), true, false, null);
if (!file.isDerived())
  file.setDerived(true);

and

resource.copy(copiedResource.getFullPath(), IResource.FORCE, null);
copiedResource.setDerived(true);
Comment 9 John Arthorne CLA 2006-01-20 11:47:11 EST
1) Already exists: IFolder.create(IResource.DERIVED, true, monitor)

2) I'm not sure when this case exists. Why wouldn't the file be derived already?  In any case, you can call setDerived(true) before setContents() to ensure the delta is correct in thise case.

3) There's no API for this, and I can see the need - I'll add that one.
Comment 10 John Arthorne CLA 2006-01-20 12:57:26 EST
I have implemented IResource#copy(IPath, IResource.DERIVED, monitor)
Comment 11 Kent Johnson CLA 2006-01-25 14:18:30 EST
Inlined senders of setDerived() where possible with new IResource.DERIVED flag.
Comment 12 David Audel CLA 2006-02-14 08:52:25 EST
Verified for 3.2 M5 using build I20060214-0010