Shrink your Jars, its easier than you think!

James just referred me to the Ant <classfileset>. It examines dependencies between your .class files and removes any of the ones you don't actually need at runtime.

Why is this useful?
Suppose you're building an app with some Jakarta libraries. Inevitably, you'll get the 2 classes you need, plus 98 you don't. Unfortunately, without <classfileset>, there's no reliable way to know which classes you can get rid of, since your 2 required classes could depend on 8 other classes.

Give me more reasons why this is useful.
With widespread adoption and understanding of the <classfileset> task, API developers like myself can be more generous in adding classes to the libraries. Without <classfileset>, each class I add to Glazed Lists increases the size of glazedlists.jar, regardless of whether anybody uses it. With the <classfileset> task, I can be somewhat more generous because the class doesn't necessarily place as much burden on disinterested users.

So is glazedlists.jar going to jump from 300K to 1.2Gb?
Not anytime soon. As far as I am concerned, the most important weight of a library is the size of the publicly exported API. It sucks when I'm reading through the Javadocs for some new library and half the classes are implementation-details and support classes for the real APIs. It also sucks when the API author can't distill the API to be as compact and learnable as possible. Since <classfileset> doesn't do anything to simplify the learning curve of a larger API, I'm not going to let our API become bloated.

Fix your JScrollPane's resizable corner under Aqua

Regular mac windows have a grippy control in the bottom right hand corner that allows you to resize the window. Unfortunately, most Swing apps don't take this control into consideration, and it's painted right over their precious scrollbar buttons! Here's two versions of the same application, before and after fixing the problem:

resize corner

Fortunately, there's a fix. Either use the most excellent quaqua look and feel, or use my simple ScrollPaneLayout hack:

* A scrollpane layout that handles the resize box in the bottom right corner.
* @author <a href="">Jesse Wilson</a>
public class MacCornerScrollPaneLayoutManager extends ScrollPaneLayout {
private static final int CORNER_HEIGHT = 14;
public static void install(JScrollPane scrollPane) {
if(System.getProperty("").startsWith("Mac")) {
scrollPane.setLayout(new MacCornerScrollPaneLayoutManager());
public void layoutContainer(Container container) {
if(!hsb.isVisible() && vsb != null) {
Rectangle bounds = new Rectangle(vsb.getBounds());
bounds.height = Math.max(0, bounds.height - CORNER_HEIGHT);

Now serving only the hottest in opensourceware: screenshot

Java 5 on Mac crashing, burning? Blame SWT, of course

I was having a weird problem with a Java Swing app crashing and burning on my Mac, with this crazy exception:
JavaAWT: NSException not handled by native method.  Passing to Java.
java.lang.RuntimeException: Non-Java exception raised, not handled! (Original problem: Error (1002) creating CGSWindow)
at apple.awt.OSXOffScreenSurfaceData._copyNSImagePixels(Native Method)
at apple.awt.OSXOffScreenSurfaceData.copyNSImagePixels(
at apple.awt.CImage.createImage(
at apple.laf.AquaImageFactory.makeAlertIcon(
at apple.laf.AquaImageFactory.getConfirmImageIcon(
at apple.laf.AquaLookAndFeel.initComponentDefaults(
at apple.laf.AquaLookAndFeel.getDefaults(
at javax.swing.UIManager.setLookAndFeel(
at javax.swing.UIManager.setLookAndFeel(
at javax.swing.UIManager.initializeDefaultLAF(
at javax.swing.UIManager.initialize(
at javax.swing.UIManager.maybeInitialize(
at javax.swing.UIManager.getUI(
at javax.swing.JPanel.updateUI(
at javax.swing.JPanel.(
at javax.swing.JPanel.(
at javax.swing.JPanel.(
at javax.swing.JRootPane.createGlassPane(
at javax.swing.JRootPane.(
at javax.swing.JFrame.createRootPane(
at javax.swing.JFrame.frameInit(
at javax.swing.JFrame.(
at com.publicobject.issuesbrowser.swing.IssuesBrowser.constructStandalone(
at com.publicobject.issuesbrowser.swing.IssuesBrowser.(
at java.awt.event.InvocationEvent.dispatch(
at java.awt.EventQueue.dispatchEvent(
at java.awt.EventDispatchThread.pumpOneEventForHierarchy(
at java.awt.EventDispatchThread.pumpEventsForHierarchy(
at java.awt.EventDispatchThread.pumpEvents(
at java.awt.EventDispatchThread.pumpEvents(

It turns out this problem occurs when you run a Swing or AWT app with SWT on your classpath. I took the SWT jars off my classpath, and everything was back to normal!