From 5f6cc719ad65eaf4d63d76bd796789bde17ac2d6 Mon Sep 17 00:00:00 2001 From: Karl Tauber Date: Wed, 12 Feb 2025 14:35:35 +0100 Subject: [PATCH] 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) --- CHANGELOG.md | 3 ++ .../java/com/formdev/flatlaf/FlatLaf.java | 50 +++++++++++++++++++ 2 files changed, 53 insertions(+) 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 map = new HashMap<>(); + for( Map.Entry e : defaults.entrySet() ) { + Object key = e.getKey(); + Object value = e.getValue(); + if( key instanceof String && ((String)key).endsWith( "UI" ) && + value instanceof String && !defaults.containsKey( value ) ) + { + String className = (String) value; + map.put( className, (LazyValue) t -> { + try { + Class uiClass = FlatLaf.class.getClassLoader().loadClass( className ); + if( ComponentUI.class.isAssignableFrom( uiClass ) ) + return uiClass; + } catch( ClassNotFoundException ex ) { + // ignore + } + + // let UIDefaults.getUIClass() try to load UI delegate class + return null; + } ); + } + } + defaults.putAll( map ); + } + private void putAATextInfo( UIDefaults defaults ) { if ( SystemInfo.isMacOS && SystemInfo.isJetBrainsJVM ) { // The awt.font.desktophints property suggests sub-pixel anti-aliasing