Native libraries: system property flatlaf.nativeLibraryPath now supports loading native libraries named the same as on Maven central; improved log messages for loading fails (issue #797)

This commit is contained in:
Karl Tauber
2024-01-24 01:02:44 +01:00
parent c85baf4dc6
commit 722dde63df
3 changed files with 82 additions and 28 deletions

View File

@@ -3,6 +3,12 @@ FlatLaf Change Log
## 3.4-SNAPSHOT ## 3.4-SNAPSHOT
#### New features and improvements
- Native libraries: System property `flatlaf.nativeLibraryPath` now supports
loading native libraries named the same as on Maven central. Improved log
messages for loading fails.
#### Fixed bugs #### Fixed bugs
- JIDE CommandMenuBar: Fixed `ClassCastException` when JIDE command bar displays - JIDE CommandMenuBar: Fixed `ClassCastException` when JIDE command bar displays

View File

@@ -172,19 +172,33 @@ public interface FlatSystemProperties
String USE_NATIVE_LIBRARY = "flatlaf.useNativeLibrary"; String USE_NATIVE_LIBRARY = "flatlaf.useNativeLibrary";
/** /**
* Specifies a directory in which the native FlatLaf libraries have been extracted. * Specifies a directory in which the FlatLaf native libraries are searched for.
* The path can be absolute or relative to current application working directory. * The path can be absolute or relative to current application working directory.
* This can be used to avoid extraction of the native libraries to the temporary directory at runtime. * This can be used to avoid extraction of the native libraries to the temporary directory at runtime.
* <p> * <p>
* If the value is {@code "system"}, then {@link System#loadLibrary(String)} is * If the value is {@code "system"} (supported since FlatLaf 2.6),
* used to load the native library. * then {@link System#loadLibrary(String)} is used to load the native library.
* Searches for the native library in classloader of caller * This searches for the native library in classloader of caller
* (using {@link ClassLoader#findLibrary(String)}) and in paths specified * (using {@link ClassLoader#findLibrary(String)}) and in paths specified
* in system properties {@code sun.boot.library.path} and {@code java.library.path}. * in system properties {@code sun.boot.library.path} and {@code java.library.path}.
* (supported since FlatLaf 2.6)
* <p> * <p>
* If the native library can not be loaded from the given path (or via {@link System#loadLibrary(String)}), * If the native library can not be loaded from the given path (or via {@link System#loadLibrary(String)}),
* then the embedded native library is extracted to the temporary directory and loaded from there. * then the embedded native library is extracted to the temporary directory and loaded from there.
* <p>
* The file names of the native libraries must be either:
* <ul>
* <li>the same as in flatlaf.jar in package 'com/formdev/flatlaf/natives' (required for "system") or
* <li>when downloaded from Maven central then as described here:
* <a href="https://www.formdev.com/flatlaf/native-libraries/">https://www.formdev.com/flatlaf/native-libraries/</a>
* (requires FlatLaf 3.4)
* </ul>
* <p>
* <strong>Note</strong>: Since FlatLaf 3.1 it is recommended to download the
* FlatLaf native libraries from Maven central and distribute them with your
* application in the same directory as flatlaf.jar.
* Then it is <strong>not necessary</strong> to set this system property.
* See <a href="https://www.formdev.com/flatlaf/native-libraries/">https://www.formdev.com/flatlaf/native-libraries/</a>
* for details.
* *
* @since 2 * @since 2
*/ */

View File

@@ -117,13 +117,32 @@ class FlatNativeLibrary
if( library.isLoaded() ) if( library.isLoaded() )
return library; return library;
LoggingFacade.INSTANCE.logSevere( "Did not find library " + libraryName + " in java.library.path, using extracted library instead", null ); LoggingFacade.INSTANCE.logSevere( "Did not find library '" + System.mapLibraryName( libraryName )
+ "' in java.library.path '" + System.getProperty( "java.library.path" )
+ "', using extracted library instead", null );
} else { } else {
// try standard library naming scheme
// (same as in flatlaf.jar in package 'com/formdev/flatlaf/natives')
File libraryFile = new File( libraryPath, System.mapLibraryName( libraryName ) ); File libraryFile = new File( libraryPath, System.mapLibraryName( libraryName ) );
if( libraryFile.exists() ) if( libraryFile.exists() )
return new NativeLibrary( libraryFile, true ); return new NativeLibrary( libraryFile, true );
LoggingFacade.INSTANCE.logSevere( "Did not find external library " + libraryFile + ", using extracted library instead", null ); // try Maven naming scheme
// (see https://www.formdev.com/flatlaf/native-libraries/)
String libraryName2 = null;
File jarFile = getJarFile();
if( jarFile != null ) {
libraryName2 = buildLibraryName( jarFile, classifier, ext );
File libraryFile2 = new File( libraryPath, libraryName2 );
if( libraryFile2.exists() )
return new NativeLibrary( libraryFile2, true );
}
LoggingFacade.INSTANCE.logSevere( "Did not find library '"
+ libraryFile.getName()
+ (libraryName2 != null ? ("' or '" + libraryName2) : "")
+ "' in '" + libraryFile.getParentFile().getAbsolutePath()
+ "', using extracted library instead", null );
} }
} }
@@ -151,6 +170,33 @@ class FlatNativeLibrary
* flatlaf-3.1-linux-x86_64.so * flatlaf-3.1-linux-x86_64.so
*/ */
private static File findLibraryBesideJar( String classifier, String ext ) { private static File findLibraryBesideJar( String classifier, String ext ) {
// get location of FlatLaf jar (or fat/uber application jar)
File jarFile = getJarFile();
if( jarFile == null )
return null;
// build library file
String libraryName = buildLibraryName( jarFile, classifier, ext );
File parent = jarFile.getParentFile();
// check whether native library exists in same directory as jar
File libraryFile = new File( parent, libraryName );
if( libraryFile.isFile() )
return libraryFile;
// if jar is in "lib" directory, then also check whether native library exists
// in "../bin" directory
if( parent.getName().equalsIgnoreCase( "lib" ) ) {
libraryFile = new File( parent.getParentFile(), "bin/" + libraryName );
if( libraryFile.isFile() )
return libraryFile;
}
// native library not found
return null;
}
private static File getJarFile() {
try { try {
// get location of FlatLaf jar // get location of FlatLaf jar
CodeSource codeSource = FlatNativeLibrary.class.getProtectionDomain().getCodeSource(); CodeSource codeSource = FlatNativeLibrary.class.getProtectionDomain().getCodeSource();
@@ -168,31 +214,19 @@ class FlatNativeLibrary
if( !jarFile.isFile() ) if( !jarFile.isFile() )
return null; return null;
// build library file return jarFile;
String jarName = jarFile.getName();
String jarBasename = jarName.substring( 0, jarName.lastIndexOf( '.' ) );
File parent = jarFile.getParentFile();
String libraryName = jarBasename
+ (jarBasename.contains( "flatlaf" ) ? "" : "-flatlaf")
+ '-' + classifier + '.' + ext;
// check whether native library exists in same directory as jar
File libraryFile = new File( parent, libraryName );
if( libraryFile.isFile() )
return libraryFile;
// if jar is in "lib" directory, then also check whether library exists
// in "../bin" directory
if( parent.getName().equalsIgnoreCase( "lib" ) ) {
libraryFile = new File( parent.getParentFile(), "bin/" + libraryName );
if( libraryFile.isFile() )
return libraryFile;
}
} catch( Exception ex ) { } catch( Exception ex ) {
LoggingFacade.INSTANCE.logSevere( ex.getMessage(), ex ); LoggingFacade.INSTANCE.logSevere( ex.getMessage(), ex );
return null;
} }
}
return null; private static String buildLibraryName( File jarFile, String classifier, String ext ) {
String jarName = jarFile.getName();
String jarBasename = jarName.substring( 0, jarName.lastIndexOf( '.' ) );
return jarBasename
+ (jarBasename.contains( "flatlaf" ) ? "" : "-flatlaf")
+ '-' + classifier + '.' + ext;
} }
private static void loadJAWT() { private static void loadJAWT() {