From 2ac7234c3285e91ae4f5b2e687534b0297c738ee Mon Sep 17 00:00:00 2001 From: Karl Tauber Date: Mon, 8 Sep 2025 13:03:17 +0200 Subject: [PATCH] support loading FlatLaf properties files from named Java modules without the need to open that package in `module-info.java` (issue #1026) --- CHANGELOG.md | 7 +++++ .../java/com/formdev/flatlaf/FlatLaf.java | 7 ++--- .../com/formdev/flatlaf/UIDefaultsLoader.java | 29 +++++++++++++++---- .../FlatModularAppTest JAR.launch | 12 ++++---- .../build.gradle.kts | 17 +++++++++++ .../modular/app/FlatModularAppTest.java | 6 +++- .../app/themes/FlatLightLaf.properties | 3 -- .../app/themes2/FlatLightLaf.properties | 17 +++++++++++ .../app/themes3/FlatLightLaf.properties | 17 +++++++++++ 9 files changed, 96 insertions(+), 19 deletions(-) create mode 100644 flatlaf-testing/flatlaf-testing-modular-app/src/main/resources/com/formdev/flatlaf/testing/modular/app/themes2/FlatLightLaf.properties create mode 100644 flatlaf-testing/flatlaf-testing-modular-app/src/main/resources/com/formdev/flatlaf/testing/modular/app/themes3/FlatLightLaf.properties diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ced8c11..7f2609b9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,13 @@ FlatLaf Change Log ## 3.7-SNAPSHOT +#### New features and improvements + +- If using `FlatLaf.registerCustomDefaultsSource( "com.myapp.themes" )` and + named Java modules, it is no longer necessary to add `opens com.myapp.themes;` + to `module-info.java`. (issue #1026) + + #### Fixed bugs - Tree and List: Fixed painting of rounded drop backgrounds. (issue #1023) 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 06601bc1..dfa9764f 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatLaf.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatLaf.java @@ -911,8 +911,7 @@ public abstract class FlatLaf *

* Invoke this method before setting the look and feel. *

- * If using Java modules, the package must be opened in {@code module-info.java}. - * Otherwise, use {@link #registerCustomDefaultsSource(URL)}. + * If using Java modules, it is not necessary to open the package in {@code module-info.java}. * * @param packageName a package name (e.g. "com.myapp.resources") */ @@ -959,9 +958,9 @@ public abstract class FlatLaf *

* See {@link #registerCustomDefaultsSource(String)} for details. *

- * This method is useful if using Java modules and the package containing the properties files - * is not opened in {@code module-info.java}. * E.g. {@code FlatLaf.registerCustomDefaultsSource( MyApp.class.getResource( "/com/myapp/themes/" ) )}. + *

+ * If using Java modules, it is not necessary to open the package in {@code module-info.java}. * * @param packageUrl a package URL * @since 2 diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/UIDefaultsLoader.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/UIDefaultsLoader.java index b13906b5..07313141 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/UIDefaultsLoader.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/UIDefaultsLoader.java @@ -205,20 +205,37 @@ class UIDefaultsLoader if( classLoader != null && !addonClassLoaders.contains( classLoader ) ) addonClassLoaders.add( classLoader ); - packageName = packageName.replace( '.', '/' ); if( classLoader == null ) classLoader = FlatLaf.class.getClassLoader(); + // Get package URL using ClassLoader.getResource(...) because this works + // also in named Java modules, even without opening the package in module-info.java. + // This extra step is necessary because ClassLoader.getResource("/.properties") + // does not work for named Java modules. + URL url = classLoader.getResource( packageName.replace( '.', '/' ) ); + if( url == null ) { + LoggingFacade.INSTANCE.logSevere( "FlatLaf: Failed to find package '" + + packageName + "' to load properties files.", null ); + continue; + } + String packageUrl = url.toExternalForm(); + if( !packageUrl.endsWith( "/" ) ) + packageUrl = packageUrl.concat( "/" ); + for( Class lafClass : lafClasses ) { - String propertiesName = packageName + '/' + simpleClassName( lafClass ) + ".properties"; - try( InputStream in = classLoader.getResourceAsStream( propertiesName ) ) { - if( in != null ) - properties.load( in ); + URL propertiesUrl = new URL( packageUrl + simpleClassName( lafClass ) + ".properties" ); + + try( InputStream in = propertiesUrl.openStream() ) { + properties.load( in ); + } catch( FileNotFoundException ex ) { + // ignore } } } else if( source instanceof URL ) { // load from package URL - URL packageUrl = (URL) source; + String packageUrl = ((URL)source).toExternalForm(); + if( !packageUrl.endsWith( "/" ) ) + packageUrl = packageUrl.concat( "/" ); for( Class lafClass : lafClasses ) { URL propertiesUrl = new URL( packageUrl + simpleClassName( lafClass ) + ".properties" ); diff --git a/flatlaf-testing/flatlaf-testing-modular-app/FlatModularAppTest JAR.launch b/flatlaf-testing/flatlaf-testing-modular-app/FlatModularAppTest JAR.launch index 10856322..10461ba4 100644 --- a/flatlaf-testing/flatlaf-testing-modular-app/FlatModularAppTest JAR.launch +++ b/flatlaf-testing/flatlaf-testing-modular-app/FlatModularAppTest JAR.launch @@ -7,6 +7,8 @@ + + @@ -17,11 +19,11 @@ - - - - - + + + + + diff --git a/flatlaf-testing/flatlaf-testing-modular-app/build.gradle.kts b/flatlaf-testing/flatlaf-testing-modular-app/build.gradle.kts index bfaf1244..dea250f2 100644 --- a/flatlaf-testing/flatlaf-testing-modular-app/build.gradle.kts +++ b/flatlaf-testing/flatlaf-testing-modular-app/build.gradle.kts @@ -30,3 +30,20 @@ flatlafModuleInfo { dependsOn( ":flatlaf-extras:jar" ) dependsOn( ":flatlaf-fonts-inter:jar" ) } + +tasks { + register( "build-for-debugging" ) { + group = "build" + + dependsOn( "build" ) + + doLast { + copy { + from( project.tasks["jar"].outputs ) + from( configurations.runtimeClasspath ) + into( "run" ) + rename( "-[0-9][0-9.]*[0-9]", "-999" ) + } + } + } +} diff --git a/flatlaf-testing/flatlaf-testing-modular-app/src/main/java/com/formdev/flatlaf/testing/modular/app/FlatModularAppTest.java b/flatlaf-testing/flatlaf-testing-modular-app/src/main/java/com/formdev/flatlaf/testing/modular/app/FlatModularAppTest.java index 301c5e6d..41ce4cb0 100644 --- a/flatlaf-testing/flatlaf-testing-modular-app/src/main/java/com/formdev/flatlaf/testing/modular/app/FlatModularAppTest.java +++ b/flatlaf-testing/flatlaf-testing-modular-app/src/main/java/com/formdev/flatlaf/testing/modular/app/FlatModularAppTest.java @@ -38,8 +38,12 @@ public class FlatModularAppTest SwingUtilities.invokeLater( () -> { FlatInterFont.installBasic(); + FlatLaf.registerCustomDefaultsSource( "com.formdev.flatlaf.testing.modular.app.themes" ); + FlatLaf.registerCustomDefaultsSource( "com.formdev.flatlaf.testing.modular.app.themes2", + FlatModularAppTest.class.getClassLoader() ); FlatLaf.registerCustomDefaultsSource( - FlatModularAppTest.class.getResource( "/com/formdev/flatlaf/testing/modular/app/themes/" ) ); + FlatModularAppTest.class.getResource( "/com/formdev/flatlaf/testing/modular/app/themes3" ) ); + FlatLightLaf.setup(); JButton button1 = new JButton( "Hello" ); diff --git a/flatlaf-testing/flatlaf-testing-modular-app/src/main/resources/com/formdev/flatlaf/testing/modular/app/themes/FlatLightLaf.properties b/flatlaf-testing/flatlaf-testing-modular-app/src/main/resources/com/formdev/flatlaf/testing/modular/app/themes/FlatLightLaf.properties index 4b52328e..7393aef8 100644 --- a/flatlaf-testing/flatlaf-testing-modular-app/src/main/resources/com/formdev/flatlaf/testing/modular/app/themes/FlatLightLaf.properties +++ b/flatlaf-testing/flatlaf-testing-modular-app/src/main/resources/com/formdev/flatlaf/testing/modular/app/themes/FlatLightLaf.properties @@ -14,7 +14,4 @@ # limitations under the License. # -@background = #fff @foreground = #f00 - -ButtonUI = com.formdev.flatlaf.testing.modular.app.plaf.MyButtonUI diff --git a/flatlaf-testing/flatlaf-testing-modular-app/src/main/resources/com/formdev/flatlaf/testing/modular/app/themes2/FlatLightLaf.properties b/flatlaf-testing/flatlaf-testing-modular-app/src/main/resources/com/formdev/flatlaf/testing/modular/app/themes2/FlatLightLaf.properties new file mode 100644 index 00000000..e077d510 --- /dev/null +++ b/flatlaf-testing/flatlaf-testing-modular-app/src/main/resources/com/formdev/flatlaf/testing/modular/app/themes2/FlatLightLaf.properties @@ -0,0 +1,17 @@ +# +# Copyright 2025 FormDev Software GmbH +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +@background = #efe diff --git a/flatlaf-testing/flatlaf-testing-modular-app/src/main/resources/com/formdev/flatlaf/testing/modular/app/themes3/FlatLightLaf.properties b/flatlaf-testing/flatlaf-testing-modular-app/src/main/resources/com/formdev/flatlaf/testing/modular/app/themes3/FlatLightLaf.properties new file mode 100644 index 00000000..f5f606a2 --- /dev/null +++ b/flatlaf-testing/flatlaf-testing-modular-app/src/main/resources/com/formdev/flatlaf/testing/modular/app/themes3/FlatLightLaf.properties @@ -0,0 +1,17 @@ +# +# Copyright 2025 FormDev Software GmbH +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +ButtonUI = com.formdev.flatlaf.testing.modular.app.plaf.MyButtonUI