Insubstantial doesn't load via custom classloader
Closed this issue · 4 comments
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. :(
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?
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;
}
@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!
Still getting the error. Yet, it turned out I was missing the trident-plugin.properties
. More info in SO.