Sunday, July 25, 2010

The experience of creating an Eclipse refactoring

A long ago I started investigating on developing new Refactorings for Eclipse. I started with a lot enthusiasm, a cup of coffee and my Linux box. First things first, I downloaded the SDK version of Eclipse. Then I started browsing the net looking for resources beside the official documentation and the code itself. I was shocked when I found out that not only there wasn't a lot of resources, they barely exist!. I can list all the resources I found right here:
That was like 2 years ago but the outlook is not very different now.  At the beginning I thought that there must be a big community of developers creating language processing tools for automating some of their stuff with JDT.  I guess I was wrong or I'm not that good at googling.

In this post I'll talk  about how I got started and I'll introduce the main components of a refactoring in eclipse in a very concise way. I want this post to be more like an entry point for someone who wants to start exploring the JDT/LTK SDK and is a little lost like I was at the time.

Originally my intention was to create a set of refactorings to promote functional programming practices in java.  First I would try to add a Quick Fix to add the final modifier to private fields that are not changed inside the class in an attemp to promote unmutable objects. I hadn't developed in java for a while and I forgot that the final modifier in java works differently then C#'s readonly which was what I had in mind when I thought of the Quick Fix. But I proceeded anyway.

Because most of the resources I had found were related to refactoring I decided to start by implementing a refactoring named 'To Final" and after that, move it to a Quick fix.

 This was my plan of action:
  1. Create the project using the wizard
  2. Invoke a dummy refactoring
  3. From that point start building the core functionality.

Creating The Project.

This is an easy one. Eclipse has a bunch template projects to get started with the SDK. I started with the good old Hello World.

The Dummy Refactoring

Turns out a Dummy Refactoring is not so Dummy after all. There are two approaches on how to build refactorings.

The old-school way
It can be done using set of classes that work together to get the job done:

This class is responsible for providing all the pages (forms) for user input, also provides the preview and an error page.

This class provides a way to create refactorings for scripting and history. I didn't use it. Because of that my plugin cannot be used in scripts.
 This is the meaty part. This class is responsible of validating that the refactoring can be performed and return an object that describes the set of changes required to complete the refactoring. The aforementioned object is an instance of the class Change that is used to generate the preview and if the changes are accepted is used to perform the actual changes in the source code.

As far as I know the RefactoringDescriptor is used with the RefactoringContribution to automate refactoring executions. In my case I ignored this one too.

Refactoring the new way
The other way to include refactorings is by The use of processors and participants. This model of adding refactorings adds the flexibility of binding partincipants to the original refactoring. It can be seen as additional tasks that the refactoring needs to execute that can exist outside of the scope of the JDT. In fact is not a new way of creating refactorings. It's an extension to the original API.

What I did in the end
I based my refactoring on the resources from the article Unleashing the Power of Refactoring. Which is based in the old-school approach.  I tried to code everything myself but I have to confess I had to go to look in the resources more times than I'd like to admit.

The core functionality

I want to leave this part to my next instalment. I'll talk about the road blocks I found during the implementation of my plugin and how I implemented it.