diff --git a/CHANGELOG.md b/CHANGELOG.md index 528d3f4a..6ce85e1e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,9 @@ FlatLaf Change Log - Linux: Popups (menus and combobox lists) were not hidden when window is moved, resized, maximized, restored, iconified or switched to another window. (issue #962) +- Fixed loading FlatLaf UI delegate classes when using FlatLaf in special + application where multiple class loaders are involved. E.g. in Eclipse plugin + or in LibreOffice extension. (issues #955 and #851) ## 3.5.4 diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatLaf.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatLaf.java index bba4d829..dec465d1 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatLaf.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatLaf.java @@ -553,6 +553,9 @@ public abstract class FlatLaf return UIScale.getUserScaleFactor(); } ); + // add lazy UI delegate class loading (if necessary) + addLazyUIdelegateClassLoading( defaults ); + if( postInitialization != null ) { postInitialization.accept( defaults ); postInitialization = null; @@ -750,6 +753,53 @@ public abstract class FlatLaf } } + /** + * Handle UI delegate classes if running in special application where multiple class loaders are involved. + * E.g. in Eclipse plugin or in LibreOffice extension. + *
+ * Problem: Swing runs in Java's system classloader and FlatLaf is loaded in plugin classloader. + * When Swing tries to load UI delegate class in {@link UIDefaults#getUIClass(String, ClassLoader)}, + * invoked from {@link UIDefaults#getUI(JComponent)}, it uses the component's classloader, + * which is Java's system classloader for core Swing components, + * and can not find FlatLaf UI delegates. + *
+ * Solution: Add lazy values for UI delegate class names. + * Those lazy values use FlatLaf classloader to load UI delegate class. + * This is similar to what {@link UIDefaults#getUIClass(String, ClassLoader)} does. + *
+ * Not using {@code defaults.put( "ClassLoader", FlatLaf.class.getClassLoader() )},
+ * which would work for FlatLaf UI delegates, but it would break custom
+ * UI delegates used in other classloaders.
+ */
+ private static void addLazyUIdelegateClassLoading( UIDefaults defaults ) {
+ if( FlatLaf.class.getClassLoader() == ClassLoader.getSystemClassLoader() )
+ return; // not necessary
+
+ Map