Archive for October, 2007

I Am The Monkey Prize Winner

I have no idea what this means, but I won the monkey prize on Woot!

Woot Monkey Prize

After my failure mocking the president of Iran, I was about to give it all up.

Perhaps there will be a new comic this week after all…

JScrollPane Blunders: Part 2

Our next blunder features a straightforward GUI, shown here:

Nested Scroll 1

The top half of the JSplitPane contains a JScrollPane, which in turn contains a JTable. Tables always need scroll panes, otherwise you won’t see the table headers. The bottom half contains another scroll pane wrapped around a JTextArea.

Dragging the splitter causes the table to scroll, exactly as expected:

Nested Scroll 2

Bring on the Blunder!

The problem is, this screen also uses nested scroll panes. This is a variation of the blunder mentioned in yesterday’s post, where you wrap the entire panel in a big scroll pane.

The difference here is that one or more scroll panes are nested somewhere inside other scroll panes. This never works correctly. Make the screen smaller and you see some really bizarre scrolling:

Nested Scroll 3

And it gets even stranger:

Nested Scroll 4

And sometimes you even get into situations where the screen starts “jittering” and shaking, as scroll bars come and go.

A Simple Rule

You simply cannot nest scroll panes inside of other scroll panes (unless perhaps one only provides horizontal scrolling, while the other provides only vertical). When the user resizes your screen, you now have BOTH scroll panes competing to see who will scroll first in order to accommodate the smaller screen real estate. When this happens, several things might happen:

  • You might see “double scroll bars” as shown above
  • In some cases the screen may jitter and shake as Swing tries to recalculate the layout
  • Things like table headers, which are supposed to be fixed, may in fact scroll away due to the outer scroll pane
  • Some panels may fail to stretch correctly, so at larger sizes you’ll see blank space instead of panels stretching to fill remaining space.

So nested scroll panes is blunder #2. You need to selectively choose regions of your screens that will expand and contract, and only use scroll panes in those regions. These are generally things like trees, tables, and text areas, but could be other components.

And finally, never blindly assume customers will run your app at 1024×768. You must resize your windows, move splitters, and force your GUI into awkward sizes to see how it reacts under pressure.

JScrollPane Blunders: Part 1

I have now witnessed one too many JScrollPane tragedies. I hope this helps.

Blunder #1 - One Giant Scroll Pane

Without a scroll pane, your Swing GUI probably looks fine at its default size. But those pesky users might try something exotic…like resizing the window. So you add a scroll pane to handle resizing gracefully. After all, scroll bars are better than vanishing components.

Here is a trivial window at its preferred size:

Big Scroll 1

And here is what happens when you make it a bit smaller…notice the scrolling:

Big Scroll 2

But the scroll pane encloses too much, which is blunder #1. The tabs even scroll away:

Big Scroll 3

When you see resizing problems, wrapping the entire panel with one giant JScrollPane is usually wrong. Most screens contain things like buttons or tabs that should not scroll.

A Small Improvement

With JTabbedPane, you generally want scroll panes inside each tab. This is a very trivial change:

Big Scroll 4

Now, the tabs do not scroll off the edge of the screen. This GUI is far from ideal, however. I found that changing the horizontal scrolling policy to JScrollPane.HORIZONTAL_SCROLLBAR_NEVER slightly improves this screen:

Big Scroll 5

Now you only see vertical scrolling. The text fields may get clipped horizontally, but only if the user makes this screen tiny.

Bonus Points?

I suppose you could really go nuts and make the text fields squish horizontally if the panel gets too narrow, but still scroll vertically as shown. I tinkered with that for a few minutes, but didn’t have much luck. One idea is to create a panel class that implements Scrollable to obtain fine-grained control over the horizontal resize behavior. Suggestions are welcome.

(Real apps usually have much bigger panels so you’ll end up with scroll panes around tables or text areas, giving your screens more natural places to expand and contract…the screen shown here is pretty unrealistic. Wrapping labels with scroll panes should be rare.)

Tease…

In coming days I plan to show at least two common scroll pane blunders. Stay tuned! Or better yet, subscribe to my Atom feed.

Gosling + Silverlight = I’m Confused

When James Gosling mentions Silverlight on his blog, is he talking about Microsoft’s Silverlight (as in a big competitor for Flash, JavaFX, etc), or something else called Silverlight?

By the way, ZFS sounds really awesome.

One More Note on Uncaught Exception Handlers

When I wrote about uncaught exception handlers on Oct 7, I omitted one important detail. If your Swing app throws an exception while displaying a modal dialog, uncaught exception handlers are not invoked.

Instead, Swing simply prints the stack trace to the console. This is troublesome in many GUI apps because your customers may not have a “console” to see these stack traces. From their perspective, absolutely nothing happens, other than your app becomes unresponsive.

Here is the reason: Swing cannot propagate an exception from the EventDispatchThread when a modal dialog is active. This would interrupt the very loop that makes the dialog modal in the first place. Here is a snippet of code from EventDispatchThread:

private void processException(Throwable e, boolean isModal) {
  if (!handleException(e)) {
    // See bug ID 4499199.
    // If we are in a modal dialog, we cannot throw
    // an exception for the ThreadGroup to handle (as added
    // in RFE 4063022).  If we did, the message pump of
    // the modal dialog would be interrupted.
    // We instead choose to handle the exception ourselves.
    // It may be useful to add either a runtime flag or API
    // later if someone would like to instead dispose the
    // dialog and allow the thread group to handle it.
    if (isModal) {
      System.err.println(
        "Exception occurred during event dispatching:");
      e.printStackTrace();
    } else if (e instanceof RuntimeException) {
      throw (RuntimeException)e;
    } else if (e instanceof Error) {
      throw (Error)e;
    }
  }
}

So how can we intercept these exceptions and show an error dialog to the user?

The secret lies in the handleException(…) method. This method looks for the existence of a system property sun.awt.exception.handler. The comments for handleException(…) define the exact requirements, but briefly:

  • The property value is a class name
  • Swing uses reflection to load the class and invoke its public no-arg constructor
  • Again, using reflection, Swing invokes the handle(Throwable t) method

Note that the comments also make it clear this property WILL GO AWAY at some point. For now, it works. Be aware that when Java 7, or 8, or 9 comes out, code relying on this implementation detail will eventually fail.

Here is how you write a Swing exception handler:

public static class AwtHandler {
  public void handle(Throwable t) {
    // do something here
  }
}

I does not have to be static…I just pasted in a snipped from my code, which happens to be static. And here is how you register your handler:

System.setProperty("sun.awt.exception.handler", AwtHandler.class.getName());

Where the comment says “do something here”, I recommend you simply delegate to your normal uncaught exception handler that I blogged about here.

HOWTO: Configure IDEA Fonts

I’m using IDEA 7 (Selena) beta, which runs under Java 6. Since Java 6 includes support for subpixel rendering, I figured fonts in IDEA would look a lot nicer. They don’t.

Hmm…after a bit of research, I found this explanation:

The good news is that JDK 6 implements this feature. Whether you use the look and feel of Metal, Microsoft Windows, or GTK, you will get the same antialiasing behavior for fonts in Java technology-based applications as you do in native applications. Best of all, you don’t have to do anything — it just works out of the box.

In order to achieve this, the look and feel of Windows and of GTK have also been updated to track the user’s desktop preferences and update any preference changes in real time. Also, the default Java technology look and feel, Metal, now reads the user’s desktop text-antialiasing preferences on startup and applies them to the JDK fonts.

What’s Wrong with IDEA?

IDEA Font Settings

Java 6 supports subpixel rendering, but only if the Look and Feel reads the user’s desktop preferences. Metal reads the preferences at startup, while Windows and GTK read them “real time” in case you make changes in Windows while your Java app is running. Out of the box (at least for me, maybe it is reading some old preferences file), IDEA uses the Alloy Look and Feel, which (from what I see on the web site) has not been updated since 2003.

Recommended Configuration

To see the subpixel rendering Goodness, go to Settings -> Appearance, and change the Look and Feel to Windows or Metal, or I suppose whatever Look and Feel is native to your platform of choice.

This changes all of the trees, menus, tabs, and dialogs to use subpixel rendering. But my editors still look like ass. The editors don’t seem to use the subpixel rendering, at least that’s what it looks like to me. I found that selecting “Use antialiased font in editor” makes the editor font look significantly better.

Finally, on Windows, my new favorite programming font is Consolas, which is bundled with Vista and available as a free download for XP. This is configured in the Settings -> Colors & Fonts dialog.

One More Thing to Try

You might also try tweaking the IDEA_HOME/bin/idea.properties file, changing the sun.java2d.noddraw value from false to true. This might improve graphics performance, but for me, it causes Vista to downgrade to some weird reduced color mode. Your mileage may vary.

You CAN Change Final Fields

Tim Vernum pointed out a mistake in my last post. I said this:

Yikes. As expected, you CANNOT change final fields. Phew! But surprisingly, attempting to set the value does not throw an exception. Instead, it silently ignores your request.

Which is completely wrong. You can change final fields. And the results are surprising to say the least, so even though you can do this, you probably should not.

Let’s Change It

Recall the Caveman class, with its final age field:

public class Caveman {
    private String name;
    private final int age = 10;

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }
}

Since the age is final and private, we must use reflection if we wish to change it:

Field ageField = Caveman.class.getDeclaredField("age");

// this lets us change private fields
ageField.setAccessible(true);

ageField.setInt(caveman, 100);

System.out.println("Age is now " + caveman.getAge());

This is where I got confused, because the program prints:

Age is now 10

My Mistake

If you run the program in a debugger and inspect the age, you will find it is actually changed to 100. The program prints 10, however, since the compiler optimized the code. Despite the fact that I used reflection to change the value, the optimized method is still…well…optimized.

As you can see, this can lead to very confusing results. For instance, you can use reflection to obtain the correct value:

System.out.println("REAL age is: " + ageField.getInt(caveman));

This gets the new 100 value, instead of the original 10.

Now Wrap Your Noodle Around This

Now change the Caveman class to initialize the age in its constructor, instead:

public class Caveman {
    private String name;
    private final int age;

    public Caveman() {
        age = 10;
    }

   ...

Now when you call the getAge() method, even after changing the field via reflection, you get the correct answer of 100.

In Summary

Here is what I learned:

  • You CAN change final fields via reflection. (yikes)
  • The compiler sometimes optimizes things, thus your programs may not see the modified data.
  • Initialization of final fields in constructors versus inline assignment can affect the optimizations.
  • You probably SHOULD NOT attempt to change final fields via reflection, because Weird Things happen.

On the Violation of Java Access Control

Let’s write a simple class and show how easy it is to bypass normal Java language access checking. This means we can modify another class’s private data using reflection. Good times…

package pkgb;

public class Caveman {
  private String name;
  private final int age = 10;

  public String getName() {
    return name;
  }

  public int getAge() {
    return age;
  }
}

Can you modify name, even thought it is private? Can you modify age, even though it is private and final?

First, What Won’t Work…

You cannot simply create a new Caveman and set its name. This will not compile because name is private. Instead, let’s try reflection:

public class Main {
  public static void main(String[] args) throws NoSuchFieldException {
    Caveman caveman = new Caveman();

    // note that getField(...) throws NoSuchFieldException
    Field nameField = Caveman.class.getDeclaredField("name");

    try {
      nameField.set(caveman, "Opie");
    } catch (IllegalAccessException e) {
      System.out.println("Unable to set name to Opie.");
    }

  ...

Notice I use getDeclaredField() instead of getField(). If you try this, you will find you are unable to set the value of the name. It is private, after all.

setAccessible(true) to the Rescue!

You need to call setAccessible(true) first:

  nameField.setAccessible(true);
  try {
    nameField.set(caveman, "Anthony");
    System.out.println("Successfully set name to " + caveman.getName());
  } catch (IllegalAccessException e) {
    // won't happen
  }

Voila! It works. This is a Good Thing, because without this capability, tools like JPA (and many others) would be severely constrained.

Can we Change the Age?

The age field is private and final. Can we use reflection to change it as well? Let’s try:

  Field ageField = Caveman.class.getDeclaredField("age");
  ageField.setAccessible(true);
  try {
    System.out.println("Setting age to 100...");
    ageField.setInt(caveman, 100);

    System.out.println("Age is now " + caveman.getAge());

    System.out.println("Is it final? " +
         Modifier.isFinal(ageField.getModifiers()));

  } catch (IllegalAccessException e) {
    System.out.println("Unable to set age.");
  }

What does the code do?

UPDATE: See this post for a correction!

It silently fails.

The console prints this:

Setting age to 100...
Age is now 10.
Is it final? true

Yikes. As expected, you CANNOT change final fields. Phew! But surprisingly, attempting to set the value does not throw an exception. Instead, it silently ignores your request.

If you need to use reflection to set field values, be sure you check the modifiers (final, etc…) before you do so.

Is this Secure?

If you are running under a SecurityManager, you might not be able to do any of this. You can verify this quite easily:

public static void main(String[] args) throws NoSuchFieldException {
  System.setSecurityManager(new SecurityManager());

  ...code just like before

Now, calling setAccessible(true) throws an exception:

Exception in thread "main" java.security.AccessControlException: access denied
  (java.lang.reflect.ReflectPermission suppressAccessChecks)
	at java.security.AccessControlContext.checkPermission
                  (AccessControlContext.java:323)
	at java.security.AccessController.checkPermission
                  (AccessController.java:546)
        etc...

So if you need to use these techniques in an app server that contains a security manager, you’ll need to edit a policy file and allow suppressAccessChecks. This isn’t my area of expertise, but I can point you to the right Google search: policy file suppressAccessChecks.

BPM: Not Even Comic-Worthy

I don’t really think this is all that funny, but describing how I could conceivably make a comic strip might clarify my opinion on John Reynold’s recent blog entry: Why Do Java Developers Hate BPM?

In this blog entry, John rehashes some really, really, really old arguments:

BPM suites make programming boring. They force you to use point-and-click and drag-and-drop tools to design your process diagrams, data models and forms. What’s worse, they actually encourage Business People to model processes and design forms on their own.

And…

BPM suites are a threat to traditional Java programmers. These suites are far from perfect, but even in their current state we can see where things are heading. The days of the Java Guru as indispensable are fading.

Just substitute the word “CASE” instead of “BPM”. Or “UML”, or “4GL”, or “MDA”. They all fit the same template argument. (maybe we could turn this into some kind of Mad Libs exercise?)

The Comic Idea

Here’s how the comic strip would look…

Frame 1 - 1981

A picture of a guy (presumably James Martin, the author) holding up his 1981 book: Application Development without Programmers. He’d be saying something along the lines of “pretty soon CASE tools will make programmers irrelevant”.

Frame 2 - 1990s

Someone hawking some UML tool or 4GL. Again, claiming “pretty soon programmers won’t be needed.”.

Frame 3 - 2000s

A guy promoting OMG Model Driven Architecture. You can guess the claim.

Frame 4 - Now

You guessed it, BPM. The same old drivel about “point and click / drag and drop” application design.

I won’t make this comic, though. Not funny. Been there, done that.

I Cannot Say It Better Than…

Check out this quote from a 2005 Computerworld blog entry:

By the time technology has advanced far enough to create a really great tool for automagically producing a broad class of applications, it also has advanced far enough to support other kinds of application functionality that the tools don’t support (except possibly through major coding).

Trust me, your job as a highly talented computer programmer is quite secure.

An Important Java 6 Memory Leak You Should Know About

We’ve spent several days now with NetBeans 6, the SAP Memory Analyzer, and other tools trying to pinpoint some pretty bad memory leaks in one of our apps. One one particular set of screens, the tools kept pointing to a modalDialogs Vector in java.awt.Dialog.

Cockroach

We just now found this discussion, leading to bug 6497929 describing the problem.

This is marked fixed, but only for Java 7. I believe this is important and deserves to be fixed in Java 6. In the meantime, the comment from John F (on bug 6497929 report) describes a very reasonable workaround that you ought to know about.