07 September 2011

Java Inline Class Definitions

Here's something in Java I came across the other day that I didn't know about: non-anonymous inline class definitions.

interface ListenerRegistration {
   void unregister();
}

List<Listener> listeners = ...;

ListenerRegistration addListener(final Listener ears)
{
   class ListenerRegImpl implements ListenerRegistration {
      public void unregister() {

         listeners.remove(ears);
      }
      void register() {
         listeners.add(ears);
      }
   }

   ListenerRegImpl reg = new ListenerRegImpl();
   reg.register();
   return reg;
}

Just as with an anonymous inline class, this class can access final variables in outside scopes, etc.
But more, this class:
  • can be declared anywhere in the block it is used, not necessarily at the top, just as with class definitions declared inside other classes
  • retains its type information allowing access to added fields and methods

This is especially useful when you need to return an instance implementing an interface, but want to use a concrete class. If the class is not used anywhere outside the scope of instantiation, the class can be defined inline, and added methods and fields are now known instead of having to use only a reference to the implemented interface.

Obviously, this example is to demonstrate a point and not the simplest way to implement the above 'addListener'. It's also not "always a good thing" as with most idioms and design patterns, use a good an appropriate tool for the job you have to accomplish.

Just another affirmation that "you don't know a language unless you program in it for 10 years".

12 January 2011

Mostly-Declarative Eclipse Perspective Folders

I came across something not long ago that I did not realize could be done with perspective layouts. In the documentation for a org.eclipse.ui.perspectiveExtensions view, the relative field has this:
the unique identifier of a view which already exists in the perspective. This will be used as a reference point for placement of the view. The relationship between these two views is defined by relationship. Ignored if relationship is "fast".
Previously, I had thought that meant strictly that only a "view id" (including the ID for the editor area) could be used here - a thought that is reinforced by the tooling which lets you select any declared view ID in scope, including the org.eclipse.ui.editorss ID.


The issue in my application was that I needed a folder in the perspective - which could only be declared by the perspective factory - to be populated with view instances (same ID, various secondary IDs) from a down-stream bundle. The perspective factory can't have a dependency on the contributing bundle, and copying the view ID string literal into the up-stream bundle was not a tolerable solution.


What I wanted was to be able to declare a page layout folder as a perspective extension, or otherwise solely in the plugin.xml files for the bundles but was unable to find a way to do this.


However, as a solution, I discovered that a new folder can be created in the perspective factory code and then the down-stream perspective extensions can reference the folder's ID as a view ID. Ah-ha!


Now the solution:

public class PerspectiveFactoryWithFolder implements IPerspectiveFactory
{
   /** A layout folder for the right side of the perspective */
   public static final String RIGHT_FOLDER = "net.bilnoski.module.ui.perspective.folder.right";
   
   public void createInitialLayout(IPageLayout layout)
   {
      layout.setEditorAreaVisible(false);
      
      layout.createPlaceholderFolder(RIGHT_FOLDER, IPageLayout.RIGHT, 0.7f, layout.getEditorArea());
   }
}
<extension
      point="org.eclipse.ui.perspectiveExtensions">
   <perspectiveExtension
         targetID="net.bilnoski.module.perspective">
      <view
            closeable="true"
            id="net.bilnoski.module2.view:*"
            minimized="false"
            moveable="true"
            relationship="stack"
            relative="net.bilnoski.module.ui.perspective.folder.right"
            showTitle="true"
            visible="true">
      </view>
   </perspectiveExtension>
</extension>


Only the folders must be declared in code, and the rest I was still able to statically in plugin.xml declarations. An acceptable compromise, especially since I needed the perspective factories to exist anyway to hide the editor area.