Steps to use Fragments to patch a plug-in
I'm at EclipseCon 2008 and have just come across a great Eclipse tip. I can't tell you how many times I've wanted to modify a little bit of Eclipse code to either fix something obvious or to modify an Eclipse class's behavior to my liking.
This tip allows me to modify any Eclipse class and ship the change with my own RCP application.
This solution uses Eclipse Fragments. An Eclipse Fragment is a way of putting your own classes into the "class loader" of another package (basically, it's as though your class was actually in the other package). If you combine this ability of a Fragment with the notion of a plugin's classpath ordering, then you can force your class to load before a like-named class in the original package. Here are the steps:
Get the package to be modified into your workspace
1) Show the class you want to edit in Eclipse (Ctrl-Shift-T, type the class name, enter)
2) Show the Plug-ins View in your workbench (Window, Show View, Other, PDE, select Plug-ins)
3) Find the corresponding package in the Plug-ins View
4) Right-mouse click the package name and select Import as Source Project
Modify the Host package Manifest settings
5) Edit the new, copied project's Manifest, go to Runtime tab, add a New... library, call it library.jar (but you can call it anything you want).
6) Move it above the '.' package so it will take precedence of the normal package files
7) On the build tab, remove the library.jar that was just added to the Runtime Information area, libraries that will be built by this package. We only want the older package to look for library.jar ...we don't want it to also create that library file; we want it to use the library.jar from our patched package (created below).
8) Now click on the manifest tab, and add Eclipse-ExtensibleAPI: true to the manifest.mf file
9) If this is a signed package, then remove the signing from the manifest.mf file (this is a somewhat optional step)
10) On the Overview tab, modify the version number so it will not conflict with the original (just in case). You might just add -MyPatch to what's there right now
* Example: 3.3.1.M20070910-0800b-MyPatch
11) Save the manifest file
Create a new Fragment project
12) Create a new fragment project: File->New->Other->Plugin Development->Fragment Project->Next. Call it whatever you'd like: org.eclipse.jface.mypatch
13) Select the host plugin ID on the next page: org.eclipse.jface
14) Finish
15) In the new fragment package, modify the manifest.mf. Edit the runtime classpath and add library.jar (or whatever you called it). It'll also auto-add the '.' after library.jar. Just leave it there.
16) Go to the manifest tab, and add Eclipse-PatchFragment: true to the manifest.mf file
17) On the build tab, remove the '.' library from the runtime information area
17a) Make sure the library.jar entry has the /src entry associated with it (click Add Folder... to find the source.)
18) Save
19) Create the same package as in the source jar file (but only for the file you want to modify)
20) Copy the file you want to your package's src->new_package folder
21) Make your changes
Run
That's really all you should have to do. However, it's always a good idea to click on "Update the Classpath Settings" on the Overview tab of the manifest editor for both the host and fragment projects.
I've noticed that when I debug, the old class is still the one that's loaded into the editor. However, I've noticed that you can overcome this limitation by copying your changed version over the original ...it's using your class file anyway, so there's no harm.
Note that at build time, you'll have to choose if you want to include your copy of the original package, with the modified manifest; or if you want to make the same manifest modifications to Eclipse's version. Up to you.
Note that using Eclipse's new Transforms mechanism is also possibly a great way of replacing class files at runtime (I haven't tried this yet). But this is only useful for Eclipse 3.4 and on. The method mentioned here works for older versions of Eclipse as well.