There seems to be a bug in the JDK1.2beta4 class loading mechanism which
prevents the loading of PLAF's (Swing Pluggable Look and Feel's) that
are not shipped as part of core. The call to Class.forName() is failing
when it is called by a core class (UIManager) to load a non-core class
(the Look and Feel).
Given the following source code:
===============
import com.sun.java.swing.*;
import com.sun.java.swing.plaf.metal.*;
public class TestPlaf extends MetalLookAndFeel {
public static void main( final String args[] ) {
try {
if( args.length == 0 ) {
UIManager.setLookAndFeel( "TestPlaf" );
}
else {
UIManager.setLookAndFeel( new TestPlaf() );
}
}
catch( final Exception e ) {
e.printStackTrace();
}
System.exit(0);
}
public TestPlaf() {
}
}
===============
The version of setLookAndFeel() that takes a string, calls
Class.forName() to load the plaf class. This will fail with a
ClassNotFoundException. Considering that we are making the call from
the class that we are trying to load, it should be impossible for this
to fail.
The call to setLookAndFeel() that takes the plaf object succeeds.
I suspect that this is due to the new delegation model used by class
loaders. The classloader that loaded our application class will
delegate to the core class loader but the reverse is not true so core
classes will not be able to load application code without explicitly
specifying which class loader to use.
This did not seem to be a problem in previous beta's.
The workaround to setLookAndFeel() is to create the instance ourselves
and pass it in. Unfortunately this doesn't fix all the problems. As
each custom ComponentUI subclass is instantiated, the class is loaded
once again by Class.forName(). Naturally this call will fail again with
a ClassNotFoundException.
The workaround here is to put an extra entry into UIDefaults. For each
custom UI put into UIDefaults there should be an extra entry where the
key is the name of the class and the value is the class object itself.
If this entry is present then UIManager will use it instead of calling
Class.forName(). For example:
defaults_.put( "ToolTipUI", "my.MyToolTipUI" );
defaults_.put( "my.MyToolTipUI", my.MyToolTipUI.class );
Mike Bowler
mbowler@GargoyleSoftware.com