Insubstantial / insubstantial

Swing look-and-feel library and assorted widgets
193 stars 57 forks source link

Insubstantial doesn't load via custom classloader #99

Closed bobbylight closed 11 years ago

bobbylight commented 11 years ago

My application uses a separate URLClassLoader to handle dynamically identifying and installing extra LookAndFeels. The actual install of the new LookAndFeel would take effect on application restart. When trying to use Insubstantial 7.1 or 7.2, I get the following stack trace:

Exception in thread "AWT-EventQueue-0" java.lang.IllegalArgumentException: No interpolator found for java.lang.Float:java.lang.Float at org.pushingpixels.trident.TimelinePropertyBuilder.getFieldInfo(TimelinePropertyBuilder.java:259) at org.pushingpixels.trident.Timeline.addPropertyToInterpolate(Timeline.java:355) at org.pushingpixels.trident.Timeline.addPropertyToInterpolate(Timeline.java:365) at org.pushingpixels.substance.internal.animation.StateTransitionTracker.onModelStateChanged(StateTransitionTracker.java:402) at org.pushingpixels.substance.internal.animation.StateTransitionTracker$4.stateChanged(StateTransitionTracker.java:264) at javax.swing.DefaultButtonModel.fireStateChanged(DefaultButtonModel.java:349) at javax.swing.DefaultButtonModel.setEnabled(DefaultButtonModel.java:209) at javax.swing.AbstractButton.setEnabled(AbstractButton.java:2088) at javax.swing.JMenuItem.setEnabled(JMenuItem.java:311) at javax.swing.AbstractAction.setEnabledFromAction(AbstractAction.java:102) at javax.swing.AbstractButton.actionPropertyChanged(AbstractButton.java:1216) at javax.swing.JMenuItem.actionPropertyChanged(JMenuItem.java:410) at javax.swing.AbstractButton$ButtonActionPropertyChangeListener.actionPropertyChanged(AbstractButton.java:1361) at javax.swing.AbstractButton$ButtonActionPropertyChangeListener.actionPropertyChanged(AbstractButton.java:1350) at javax.swing.ActionPropertyChangeListener.propertyChange(ActionPropertyChangeListener.java:88) at java.beans.PropertyChangeSupport.fire(PropertyChangeSupport.java:335) at java.beans.PropertyChangeSupport.firePropertyChange(PropertyChangeSupport.java:327) at javax.swing.event.SwingPropertyChangeSupport.firePropertyChange(SwingPropertyChangeSupport.java:92) at java.beans.PropertyChangeSupport.firePropertyChange(PropertyChangeSupport.java:263) at javax.swing.AbstractAction.firePropertyChange(AbstractAction.java:276) at javax.swing.AbstractAction.setEnabled(AbstractAction.java:236) at org.pushingpixels.substance.internal.utils.SubstanceTitlePane.setState(SubstanceTitlePane.java:1088) at org.pushingpixels.substance.internal.utils.SubstanceTitlePane.setState(SubstanceTitlePane.java:1002) at org.pushingpixels.substance.internal.utils.SubstanceTitlePane.addNotify(SubstanceTitlePane.java:653) at java.awt.Container.addNotify(Container.java:2769) at javax.swing.JComponent.addNotify(JComponent.java:4743) at java.awt.Container.addNotify(Container.java:2769) at javax.swing.JComponent.addNotify(JComponent.java:4743) at javax.swing.JRootPane.addNotify(JRootPane.java:756) at java.awt.Container.addNotify(Container.java:2769) at java.awt.Window.addNotify(Window.java:769) at java.awt.Frame.addNotify(Frame.java:487) at java.awt.Window.pack(Window.java:806) at org.fife.rtext.RText.setIconGroupByName(RText.java:1256) at org.fife.rtext.RText.preToolBarInit(RText.java:1074) at org.fife.ui.app.AbstractGUIApplication$StartupRunnable.run(AbstractGUIApplication.java:1375) at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:251) at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:705) at java.awt.EventQueue.access$000(EventQueue.java:101) at java.awt.EventQueue$3.run(EventQueue.java:666) at java.awt.EventQueue$3.run(EventQueue.java:664) at java.security.AccessController.doPrivileged(Native Method) at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76) at java.awt.EventQueue.dispatchEvent(EventQueue.java:675) at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:211) at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:128) at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:117) at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:113) at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:105) at java.awt.EventDispatchThread.run(EventDispatchThread.java:90)

If I put all substance/trident jars on the main application classpath, everything works fine (probably just the one with interpolators is all that matters).

This prevents folks like me from having applications that dynamically load LookAndFeels from using Insubstantial. We have to have hard dependencies in place.

IIRC, I had to fix at least one ClassLoader issue with the "original" Substance builds myself to get something like this working, but that little experience was long-since thrown away. :(

shemnon commented 11 years ago

It looks to me trident is using the thread context class loader to load some of the interpolators it uses (https://github.com/Insubstantial/insubstantial/blob/master/trident/src/main/java/org/pushingpixels/trident/TridentConfig.java#L82). If I were to add a system property that said "Use the getClass().getClassLaoder()" instead would that work? Or does each jar get it's own classloader?

kschaefe commented 11 years ago

Not sure if this is going to be 100% on point, but this is the code I use in the SwingX LookAndFeelAddons class for obtaining the correct ClassLoader:

private static ClassLoader getClassLoader() {
    ClassLoader cl = null;

    try {
        cl = AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
            @Override
            public ClassLoader run() {
                return LookAndFeelAddons.class.getClassLoader();
            }
        });
    } catch (SecurityException ignore) { }

    if (cl == null) {
        final Thread t = Thread.currentThread();

        try {
            cl = AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
                @Override
                public ClassLoader run() {
                    return t.getContextClassLoader();
                }
            });
        } catch (SecurityException ignore) { }
    }

    if (cl == null) {
        try {
            cl = AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
                @Override
                public ClassLoader run() {
                    return ClassLoader.getSystemClassLoader();
                }
            });
        } catch (SecurityException ignore) { }
    }

    return cl;
}
bobbylight commented 11 years ago

@shemnon, I think that would work (the system property idea you suggested). I'll try doing a custom build myself to see if it works my specific case. Never used gradle before, wish me luck!

dgarkov commented 8 years ago

Still getting the error. Yet, it turned out I was missing the trident-plugin.properties. More info in SO.