FontChooser and Member Access Rules by Daniel Horn

By: Daniel Horn

Abstract: This paper discusses how to take a useful Java class, FontChooser, and extend its features even though the visibility and member access modifiers would ordinarily prevent one from doing so.

Introduction:

Among the many useful classes provided by JBuilder is one called FontChooser which makes it easy to display a dialog box from which a user can select a font. 

In a recent project in which I used FontChooser, I encountered some limitations with this class. I wished to change its default behavior in two ways by:  

  • changing the default size of the dialog box, and 
  • adding a checkbox with which the user could indicate a default setting.  

One might think that the solution to this would be to derive a new class from FontChooser, but things are not as simple as that.  First of all, FontChooser is not a Dialog, nor even a Panel; it's just an Object.  When the user makes the call to FontChooser.showDialog(), an instance of a FontChooserDialog is created to display the information represented by the FontChooser.  There are two problems here:  first, FontChooserDialog is a non-public class defined in FontChooser.java which means that access to it is restricted to members of the same package, com.borland.dbswing; second, even if we could derive from the FontChooserDialog class, the FontChooser class provides no way to assign it as its dialog. 

This note will demonstrate a loophole in the member access settings in FontChooser.java that let me workaround these limitations and provide the functionality I needed.

 

 

Caveats:

The example code for this note was written and tested with JBuilder 9 Enterprise.  It is important to remember that there is no guarantee that this code will work with future versions of JBuilder as Borland may change com.borland.dbswing.FontChooser at some point in the future.

As software source code copyrighted by Borland, there are licensing issues and limitations with respect to using FontChooser.java.  Please check the license terms that come with your version of JBuilder before redistributing any program or code based on the specific code provided here.  The MyFontChooser.java code derived from FontChooser.java is meant solely as an example of how to workaround member access settings in certain situations.

 

 

The Sample Program:

The source code (https://codecentral.borland.com/codecentral/ccWeb.exe/listing?id=21058) for a sample Java application, the FontChooserDemoApplication, demonstrates how to use a class called MyFontChooser that is derived from FontChooser.  There's not much to the program:  run it and choose the Options | Fonts... menu item to see the modified font display dialog.

 

 

How It Works:  

MyFontChooser.java overrides the FontChooser.showDialog() method to apply a "PreferredSize" property to the dialog box and to apply the "Reset fonts to defaults" functionality if the checkbox is selected when the OK button is pressed.  Rather than cut and paste functionality from the FontChooserDialog class defined in FontChooser.java, I just use this class.

But what a minute... didn't I say earlier that deriving from the FontChooser class wouldn't work?

Well that's true... except if the MyFontChooser class is defined within the same package as FontChooser, namely com.borland.dbswing.  Just because this package comes from somewhere else, there's nothing to prevent the compiler from being fooled that code that I write is part of that package.

Most of the code written is in showDialog() and most of that simply duplicates functionality in the base class version.  There are a few differences because of the new functionality added.  The rest of the differences are the result of using accessor functions to obtain private members in the base class.  For example, code that reads

if (availableFonts != null) {
    dialog.setAvailableFonts(availableFonts);
}

in the base class version of the function, needs to be replaced by

Font[] availableFonts = getAvailableFonts();
if (availableFonts != null)
{
    dialog.setAvailableFonts(availableFonts);
}

in the derived class.

See MyFontChooser.java for the rest of the details.

See the jMenuItemFonts_actionPerformed method in FontChooserDemoFrame.java for sample code on using this class and how to set its preferred size.

Also, don't be fooled by the "frame" and "setFrame()"  members in FontChooser.  The "frame" is merely used as a window relative to which the FontChooserDialog is positioned.  Take a look at showDialog() and you'll see that if you prefer to, say, always have the dialog centered in the screen, then the dependency on the "frame" could easily be removed.

 

 

Summary:

This example was not presented as a recommended way of working around member access restrictions placed by a base class but as a reminder that the member access constructs in the programming language are really guidelines as to how the members are to be used.  Unless a member is labeled "private", it can be accessed by using the same trick I used for dbswing (i.e., by deriving a new class within the same package). 

Don't confuse member access rules with security; for example, user name and password credentials stored as non-private members of a (non-final) class can be read using this technique.

A better solution for attaining the functionality I want added would be to have the class vendor, Borland, make changes to FontChooser and FontChooserDialog that let developers customize them (hint, hint).  In particular, this would include changing FontChooserDialog to public (so that it can be derived from) and changing FontChooser so that the showDialog() can display an assigned dialog (derived from FontChooserDialog).

Questions, comments, and suggestions may be sent to the author at [email protected] ; use the title of the article or the words BDN Article in the email subject.


Server Response from: ETNASC03