Jump to: navigation, search

Difference between revisions of "DTP Message Bundle Conversion Tool"

m (Dynamic constructed keys: Replace loop with getDeclaredField -- shorter code and better performance (at least on my JRE))
Line 88: Line 88:
 
       {
 
       {
 
         Class c = Messages.class;
 
         Class c = Messages.class;
         Field[] fields = c.getDeclaredFields();
+
         try {
        for(int i=0;i<fields.length;i++)
+
            Field field = c.getDeclaredField(fieldName);
        {
+
             return (String)field.get(null);
             if(fields[i].getName().equals(fieldName))
+
        } catch (Exception e) {
            {
+
            return "!" + fieldName + "!";
                try
+
                {
+
                    return (String)fields[i].get(null);
+
                }
+
                catch(Exception ex)
+
                {
+
                    return "!" + fieldName + "!";
+
                }
+
            }
+
 
         }
 
         }
        return "!" + fieldName + "!";
+
      }
    }
+
 
</pre>
 
</pre>

Revision as of 14:19, 11 October 2007

Back to DTP Main Page

Introduction

Starting from eclipse 3.1, a new type of resource bundle story is used to improve performance and provide other benefits such as: easily catch missing keys, and find unused keys. The eclipse platform core team provided a tool to aid the developers and I’ve made some improvements to it, which you can find at: I've used it in DTP to convert message bundles in some SQL Dev Tools plug-ins. This document gives an overview of how the converter can be used. You can find more about the new message bundle itself from this URL: Eclipse 3.1 Message Bundles

Improvements

You can download the modified converter from here. I have modified the tool in the following ways:

File comments

Keep the original legal declaration.

Default resouce bundle

Whenever you invoke the converter actions on a resource bundle class, a dialog will popup for you to select the corresponding resource bundle. The new tools will automatically select the messages.properties resource bundle in the same package to save your time.

Find missing keys

A new action Check missing keys... is added to the context menu when you right click on a resource bundle class. This action will compare the class with the resource bundle to search the fields that exist in the class but not in the resource bundle. If such missing keys are found, a dialog will popup with all the missing keys and you can copy them into the resource bundle to define the values.

Catch exceptions

Sometimes the refactor can not be performed successfully. The old tool just fails silently in such cases. The new tool will catch the exceptions during refactoring so that the conversion can continue. Of course, when the refactoring is done, you will find errors, which needs your manual modification.

Benefits

Using the conversion tool, it’s easy to identify the following problems:

Find duplicate keys

After the conversion, if you have duplicate keys, you will find duplicate field declarations in the resource bundle class, which shows as compilation errors.

Missing keys

During the refactoring, all the Messages.getString("abc") calls are converted into Messages.abc, If you haven’t defined such a resource in the resource bundle, you will get compilation errors.

Incorrect resource bundle calls

If the conversion can not proceed successfully, it may due to incorrect resource bundle calls, such as getString(""), which doesn’t use any key as the parameter.

Incorrect resource bundle reference

If you have multiple Messages.java in different packages, it’s easy to reference the wrong resource bundle using the standard Java ResourceBundles approach. But with the new approach, you will easily find this problem.

Conversion

Preparation

Note that the message bundle access class is replaced when the tool is run. If you define extra code, constants, etc in that class then please read the notes below to ensure that you don't have problems.

Backup

The easiest way to protect your work is to backup before you proceed.

Extra helper methods

When using the NLS tooling from previous Eclipse releases, the java file which was created had the format of the "old" Messages.java file as described above. (basic class with #getString(String) method) Some plug-in owners have created extra helper methods on the class to aid in their message bundle lookup. Since the conversion tool has only basic functionality, these plug-in developers must perform a couple of extra steps before running the tool. Essentially what you want to do is get your java file into the basic template form. This is possible via using existing refactorings. For instance, if your class defines a method like this:

public String getString(String key, Object binding) {
    return MessageFormat.format(getString(key), new Object[] {binding});
}

Then you want to do the following: Change the method body to be: return NLS.bind(getString(key), binding); Select the method name and from the context menu choose the "Inline" refactoring. This will replace calls to this method in your code with calls to the code in step 1. A small tip: the accelerator key for "Inline" is ALT+SHIFT+I.

Compilation errors

Please fix all compilation errors before using the tool, otherwise the refactoring will fail.

Steps

Here are the steps to use when converting your code. Download the modified version of the convertion tool and install the plug-in. Run Eclipse. Synchronize with the repository. (you will be using the Synchronize view as your compare browser to view changes) Select your message bundle access class. (e.g. the class which has the #getString(String) method in it) From the context menu, choose "Convert to New Bundle". Choose the class's associated .properties file from the resulting "Open Resource..." dialog. Use the Synchronize view to review the changes. Release the new code.

Post Processing

Editor messages

Actions extending org.eclipse.ui.texteditor.ResourceAction need a resource bundle as the parameter to the constructor. In this case, you need to separate the messages into 2 resource bundles. E.g. one is called "messages.properties", which holds messages used by the fields in the resource bundle access class; the other is called "ConstructedEditorMessages.properties", which holds messages used by the ResourceActions. Below is the code snippet in the resource bundle access class:

public final class Messages extends NLS {
        private static final String BUNDLE_FOR_CONSTRUCTED_KEYS= "org.eclipse.datatools.sqltools.internal.sqlscrapbook.editor.ConstructedEditorMessages";//$NON-NLS-1$
        private static ResourceBundle fgBundleForConstructedKeys= ResourceBundle.getBundle(BUNDLE_FOR_CONSTRUCTED_KEYS);

        /**
         * Returns the message bundle which contains constructed keys.
         *
         * @return the message bundle
         */
        public static ResourceBundle getBundleForConstructedKeys() {
                return fgBundleForConstructedKeys;
        }

        private static final String BUNDLE_NAME = "org.eclipse.datatools.sqltools.internal.sqlscrapbook.editor.messages";//$NON-NLS-1$
...

Dynamic constructed keys

Sometimes we need to construct a key dynamically, such as: getString("key" + i), where i is an integer. We have 2 ways to handle this problem: reflection and switch case. The following is a code snippet of the reflection approach:

      /**
       * Gets a resource string by field name. This is useful when the field name is constructed ad hoc.
       * @param fieldName
       * @return
       */
      public static String getString(String fieldName)
      {
        Class c = Messages.class;
        try {
            Field field = c.getDeclaredField(fieldName);
            return (String)field.get(null);
        } catch (Exception e) {
            return "!" + fieldName + "!";
        }
      }