Howardism Musings from my Awakening Dementia
My collected thoughts flamed by hubris
Home PageSend Comment
Localize String

In converting old code like this:

log.info ( "Trying to parse "+file+" into a "+type );

Into something that is more localizable, like either:

final Object[] parms = { file, type };
final String template = "Trying to parse {0} into a {1}";
final String message = MessageFormat.format ( template, parms );
log.info ( message );

Or, an inlined version of that without all of the variables:

log.info ( MessageFormat.format 
  ( "Trying to parse {0} into a {1}", 
    new Object[] { file, type } ) );

I wrote this script that allows me to highlight the original string with all of the concatenations and have it convert it for me.

Document Field

I had to create valid Javadocs for files full of static variables … Java's feeble attempt at constants. While I could go through and type them all in, most of them were pretty self explanatory … if you just had the value of the static in the Javadocs. You know, something like:

/**
 * The 'EOF' keyword with a value of '0'
 */
public static final String EOF = 0;

It didn't take long to whip up this script. You'll want to change that string in the middle to something more helpful to you.

Heavy Refactoring with Eclipse Monkey

Refactoring code in Eclipse has really changed the way I maintain code. I often extract code into a local variable or inline the values of local variables just to see which is easier to read and understand… for code that is easier to understand is easier to maintain.

But what about refactoring code that can't be automatically converted?

At work, we've code a collection of classes which begin by logging a message after crafting a long string of the parameters. Something along the lines of:

logStart ( "host="+host +" port="+port +
           " user='"+user +"' pass='"+pass+"'" );

However, each developer who wrote each of these classes would usually write them slightly differently. Now, for a logging message, normally this wouldn't be a big deal, but for this product, it is customer facing, and we decided that it would be better if did something like:

logStart ( new Object[] { host, port, user, pass } );

Or, with the new variable argument feature in Java 5, this would end up as:

logStart ( host, port, user, pass );

But how to convert all of those classes? This is where my old friend, Emacs, often comes into play. For I could write a little bit of code to programmatically convert these kinds of lines, bind it to a key, and kick it off.

Unfortunately, macros and this sort of thing is not standard on Eclipse.

But a new project, Eclipse Monkey, while a bit difficult to figure out, works quite well.

First, you need to install Eclipse Monkey, and the online instructions are quite easy to get started. Once it is installed and Eclipse has restarted, you'll have a Scripts menu. Select the Examples and it will create a new project (Eclipse Monkey Examples) full of examples.

Clicking again on the Scripts menu will now display a larger collection of example scripts that exist in the scripts directory in that project. In fact, any project that contains a directory called scripts will be searched and scripts found there will be added to that directory (see this document).

The scripts (while eventually can be written in just about any scripting language) are written in Javascript, but these scripts have access to both the Eclipse RCP as well as to Java. The rub is knowing where you are and what you can do.

First, create a comment header of the metadata containing information like the name used on the menu and a keystroke we can use to bring it up without needing to use the menu:

/*
 * Menu: Convert showExec() Methods 
 * Key: M3+9
 * DOM: http://download.eclipse.org/technology/dash/update/org.eclipse.eclipsemonkey.lang.javascript
 */

A critical line is the DOM entry. This specifies a… uhm, library for our script to use, and in this case, this DOM creates a good interface to the Eclipse RCP to get us started.

Note: The biggest problem with Monkey right now is the lack of generated documentation of this and any DOM. I would hope that eventually, putting the URL of the DOM in your browser would at least bring up a Javadoc-like listing of the objects available.

Next, let's create our main() method, which will be called when this script is executed, and the first thing we will do, is use the DOM we just included to get the active editor:

function main() {

    var editor = editors.activeEditor;

What can we do with it? In my case, I deprecated the first logStart method above in favor with the second form, so when I load up a class with the first form, I can simply hit Control-. to jump to that line, and have the deprecated method highlight. So, in my script, I want to grab the highlighted text:

    var range  = editor.selectionRange;
    var offset = range.startingOffset; 
    var deleteLength = range.endingOffset - offset;

    var text = editor.source.substring( offset, range.endingOffset )

We get the range (and assign some variables we will be using), and then get some of the source from the editor based on the highlighted range.

At this point, we are in the happy place of Javascriptland, and there are plenty of books and online documentation on this aspect. In this example, I wanted to use the text substitution and regular expressions to convert this text:

    text = text.replace( /"[^"]+"\s*\+\s*/, "new Object[] { ")
    text = text.replace( /\s*\+\s*"[^"]+"\s*\+\s*/g, ", ")
    text = text.replace( /\s*\+\s*"[^"]+"\s*\)/, ")")
    text = text.substring ( 0, text.lastIndexOf(")") ) + " } )"

While you are developing and debugging your script, I would recommend using the following line to see what you are variable text contains:

    // Packages.org.eclipse.jface.dialogs.MessageDialog.openInformation(    
    //     window.getShell(), "Monkey Debugging", text )

This will open up a dialog window with the contents of the text variable as the contents of the dialog. I can then highlight the bad code, hit Alt-9, and see what my script was going to do with my code. Once I was happy with the results, I commented out the dialog code above and added the applyEdit code:

    editor.applyEdit(offset, deleteLength, text);
}

With this script bound to a keystroke, I could load up a file and easily convert it, and then spend less of my time with tedious text-smithing.

Hopefully this project will expand, for its a great idea, and its biggest problem is the lack of documentation. As I play and search the 'net for examples, I'll start documenting them here.

Tell others about this article:
Click here to submit this page to Stumble It