[Git][java-team/libjna-java][upstream] 4 commits: New upstream version 5.16.0

Emmanuel Bourg (@ebourg) gitlab at salsa.debian.org
Sun Mar 15 19:53:02 GMT 2026



Emmanuel Bourg pushed to branch upstream at Debian Java Maintainers / libjna-java


Commits:
95f1ef45 by Emmanuel Bourg at 2026-03-15T19:51:20+01:00
New upstream version 5.16.0
- - - - -
c701eadd by Emmanuel Bourg at 2026-03-15T19:55:09+01:00
New upstream version 5.17.0
- - - - -
e488f65b by Emmanuel Bourg at 2026-03-15T20:25:24+01:00
New upstream version 5.18.0
- - - - -
61b94c20 by Emmanuel Bourg at 2026-03-15T20:25:30+01:00
New upstream version 5.18.1
- - - - -


17 changed files:

- CHANGES.md
- LICENSE
- README.md
- build.xml
- common.xml
- contrib/platform/build.xml
- contrib/platform/src/com/sun/jna/platform/mac/CoreFoundation.java
- contrib/platform/src/com/sun/jna/platform/unix/solaris/Kstat2.java
- contrib/platform/src/com/sun/jna/platform/win32/WinNT.java
- contrib/platform/src/com/sun/jna/platform/win32/WinUser.java
- contrib/platform/test/com/sun/jna/platform/linux/UdevTest.java
- contrib/platform/test/com/sun/jna/platform/mac/CoreFoundationTest.java
- contrib/platform/test/com/sun/jna/platform/win32/User32Test.java
- native/Makefile
- src/com/sun/jna/Platform.java
- src/com/sun/jna/Structure.java
- src/com/sun/jna/overview.html


Changes:

=====================================
CHANGES.md
=====================================
@@ -2,6 +2,51 @@ NOTE: as of JNA 4.0, JNA is now dual-licensed under LGPL and AL 2.0 (see LICENSE
 
 NOTE: JNI native support is typically incompatible between minor versions, and almost always incompatible between major versions.
 
+Release 5.18.1
+==============
+
+Bug Fixes
+---------
+* [#1686](https://github.com/java-native-access/jna/issues/1686): Fix `sortFields` race condition while getting fields - [@bendk](https://github.com/bendk).
+
+Release 5.18.0
+==============
+
+Features
+--------
+* [#1671](https://github.com/java-native-access/jna/pull/1671): Add `isRISCV` to `c.s.j.Platform` - [@Glavo](https://github.com/Glavo).
+* [#1672](https://github.com/java-native-access/jna/pull/1672): Add `CFLocale`, `CFLocaleCopyCurrent`, `CFCFDateFormatter`, `CFDateFormatterStyle`, `CFDateFormatterCreate` and `CFDateFormatterGetFormat` to `c.s.j.p.mac.CoreFoundation` - [@dbwiddis](https://github.com/dbwiddis).
+* [#1669](https://github.com/java-native-access/jna/pull/1669): Document requirement for running on JDK 24+ - [@matthiasblaesing](https://github.com/matthiasblaesing).
+
+Bug Fixes
+---------
+* [#1681](https://github.com/java-native-access/jna/issues/1681): Fix deadlock in Structure constructor introduced in 5.16.0 - [@brettwooldridge](https://github.com/brettwooldridge).
+* [#1683](https://github.com/java-native-access/jna/pull/1683): Fix native build error on Xcode 16.3 / Apple Clang 17 - [@brettwooldridge](https://github.com/brettwooldridge).
+
+
+Release 5.17.0
+==============
+
+Features
+--------
+* [#1658](https://github.com/java-native-access/jna/pull/1658):  Add win32 power event constants, types, and functions - [@eranl](https://github.com/eranl).
+
+Bug Fixes
+---------
+* [#1647](https://github.com/java-native-access/jna/issues/1647): Fix calls to jnidispatch on Android with 16KB page size (part 2) - [@BugsBeGone](https://github.com/BugsBeGone).
+
+
+Release 5.16.0
+==============
+
+Features
+--------
+* [#1626](https://github.com/java-native-access/jna/pull/1626): Add caching of field list and field validation in `Structure` along with more efficient reentrant read-write locking instead of synchronized() blocks - [@BrettWooldridge](https://github.com/brettwooldridge)
+
+Bug Fixes
+---------
+* [#1618](https://github.com/java-native-access/jna/issues/1618): Fix calls to jnidispatch on Android with 16KB page size - [@Thomyrock](https://github.com/Thomyrock)
+
 Release 5.15.0
 ==============
 


=====================================
LICENSE
=====================================
@@ -1,4 +1,4 @@
-SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1
+SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later
 
 Java Native Access (JNA) is licensed under the LGPL, version 2.1
 or later, or (from version 4.0 onward) the Apache License,


=====================================
README.md
=====================================
@@ -7,7 +7,7 @@
 Java Native Access (JNA)
 ========================
 
-The definitive JNA reference (including an overview and usage details) is in the [JavaDoc](http://java-native-access.github.io/jna/5.15.0/javadoc/).  Please read the [overview](http://java-native-access.github.io/jna/5.15.0/javadoc/overview-summary.html#overview_description).  Questions, comments, or exploratory conversations should begin on the [mailing list](http://groups.google.com/group/jna-users), although you may find it easier to find answers to already-solved problems on [StackOverflow](http://stackoverflow.com/questions/tagged/jna).
+The definitive JNA reference (including an overview and usage details) is in the [JavaDoc](http://java-native-access.github.io/jna/5.18.1/javadoc/).  Please read the [overview](http://java-native-access.github.io/jna/5.18.1/javadoc/overview-summary.html#overview_description).  Questions, comments, or exploratory conversations should begin on the [mailing list](http://groups.google.com/group/jna-users), although you may find it easier to find answers to already-solved problems on [StackOverflow](http://stackoverflow.com/questions/tagged/jna).
 
 JNA provides Java programs easy access to native shared libraries without writing anything but Java code - no JNI or native code is required. This functionality is comparable to Windows' Platform/Invoke and Python's ctypes.
 
@@ -66,12 +66,12 @@ Pre-built platform support may be found [here](https://github.com/java-native-ac
 Download
 ========
 
-Version 5.15.0
+Version 5.18.1
 
 JNA
 ---
 
-[![Maven Central](https://img.shields.io/maven-central/v/net.java.dev.jna/jna.svg?label=Maven%20Central)](https://search.maven.org/artifact/net.java.dev.jna/jna/5.15.0/jar) [jna-5.15.0.jar](https://repo1.maven.org/maven2/net/java/dev/jna/jna/5.15.0/jna-5.15.0.jar) [jna-jpms-5.15.0.jar](https://repo1.maven.org/maven2/net/java/dev/jna/jna-jpms/5.15.0/jna-jpms-5.15.0.jar)
+[![Maven Central](https://img.shields.io/maven-central/v/net.java.dev.jna/jna.svg?label=Maven%20Central)](https://search.maven.org/artifact/net.java.dev.jna/jna/5.18.1/jar) [jna-5.18.1.jar](https://repo1.maven.org/maven2/net/java/dev/jna/jna/5.18.1/jna-5.18.1.jar) [jna-jpms-5.18.1.jar](https://repo1.maven.org/maven2/net/java/dev/jna/jna-jpms/5.18.1/jna-jpms-5.18.1.jar)
 
 This is the core artifact of JNA and contains only the binding library and the
 core helper classes.
@@ -79,7 +79,7 @@ core helper classes.
 JNA Platform
 ------------
 
-[![Maven Central](https://img.shields.io/maven-central/v/net.java.dev.jna/jna-platform.svg?label=Maven%20Central)](https://search.maven.org/artifact/net.java.dev.jna/jna-platform/5.15.0/jar) [jna-platform-5.15.0.jar](https://repo1.maven.org/maven2/net/java/dev/jna/jna-platform/5.15.0/jna-platform-5.15.0.jar) [jna-platform-jpms-5.15.0.jar](https://repo1.maven.org/maven2/net/java/dev/jna/jna-platform-jpms/5.15.0/jna-platform-jpms-5.15.0.jar)
+[![Maven Central](https://img.shields.io/maven-central/v/net.java.dev.jna/jna-platform.svg?label=Maven%20Central)](https://search.maven.org/artifact/net.java.dev.jna/jna-platform/5.18.1/jar) [jna-platform-5.18.1.jar](https://repo1.maven.org/maven2/net/java/dev/jna/jna-platform/5.18.1/jna-platform-5.18.1.jar) [jna-platform-jpms-5.18.1.jar](https://repo1.maven.org/maven2/net/java/dev/jna/jna-platform-jpms/5.18.1/jna-platform-jpms-5.18.1.jar)
 
 This artifact holds cross-platform mappings and mappings for a number of commonly used platform
 functions, including a large number of Win32 mappings as well as a set of utility classes
@@ -147,12 +147,12 @@ Using the Library
 * [Platform Library](https://github.com/java-native-access/jna/blob/master/www/PlatformLibrary.md)
 * [Direct Method Mapping](https://github.com/java-native-access/jna/blob/master/www/DirectMapping.md) (Optimization)
 * [Frequently Asked Questions (FAQ)](https://github.com/java-native-access/jna/blob/master/www/FrequentlyAskedQuestions.md)
-* [Avoiding Crashes](http://java-native-access.github.io/jna/5.15.0/javadoc/overview-summary.html#crash-protection)
+* [Avoiding Crashes](http://java-native-access.github.io/jna/5.18.1/javadoc/overview-summary.html#crash-protection)
 
 Primary Documentation (JavaDoc)
 ===============================
 
-The definitive JNA reference is in the [JavaDoc](http://java-native-access.github.io/jna/5.15.0/javadoc/).
+The definitive JNA reference is in the [JavaDoc](http://java-native-access.github.io/jna/5.18.1/javadoc/).
 
 Developers
 ==========


=====================================
build.xml
=====================================
@@ -75,10 +75,8 @@
   <property name="platform-jpms-jar" value="${dist}/jna-platform-jpms.jar" />
 
   <!-- defined maven snapshots and staging repository id and url -->
-  <property name="maven-snapshots-repository-id" value="oss.sonatype.org" />
-  <property name="maven-snapshots-repository-url" value="https://oss.sonatype.org/content/repositories/snapshots/" />
-  <property name="maven-staging-repository-id" value="oss.sonatype.org" />
-  <property name="maven-staging-repository-url" value="https://oss.sonatype.org/service/local/staging/deploy/maven2/" />
+  <property name="maven-snapshots-repository-id" value="sonatype-central-portal-snapshots" />
+  <property name="maven-snapshots-repository-url" value="https://central.sonatype.com/repository/maven-snapshots/" />
 
   <!-- Miscellaneous -->
   <property name="build" value="build"/>
@@ -398,6 +396,10 @@ com/sun/jna/freebsd-x86-64/libjnidispatch.so;
 processor=x86-64;osname=freebsd,
 com/sun/jna/freebsd-aarch64/libjnidispatch.so;
 processor=aarch64;osname=freebsd,
+com/sun/jna/freebsd-ppc64le/libjnidispatch.so;
+processor=ppc64le;osname=freebsd,
+com/sun/jna/freebsd-ppc64/libjnidispatch.so;
+processor=ppc64;osname=freebsd,
 
 com/sun/jna/openbsd-x86/libjnidispatch.so;
 processor=x86;osname=openbsd,
@@ -420,6 +422,7 @@ osname=macosx;processor=aarch64
               <attribute name="Multi-Release" value="true"/>
           </manifest>
           <manifest file="@{target}" mode="update" unless:true="@{module-info}">
+              <attribute name="ModuleMainClass" value="com.sun.jna.Native"/>
               <attribute name="Automatic-Module-Name" value="com.sun.jna"/>
           </manifest>
       </sequential>
@@ -429,6 +432,7 @@ osname=macosx;processor=aarch64
     <build-manifest target="${build}/manifest/module.mf" module-info="true"/>
     <build-manifest target="${build}/manifest/automatic.mf" module-info="false"/>
     <ModuleGenerator
+        mainClass="com.sun.jna.Native"
         targetFile="${build}/manifest/module-info.class"
         name="com.sun.jna"
         version="${jna.major}.${jna.minor}.${jna.revision}"
@@ -535,6 +539,12 @@ osname=macosx;processor=aarch64
       <zipfileset src="${lib.native}/freebsd-aarch64.jar"
                   includes="*jnidispatch*"
                   prefix="com/sun/jna/freebsd-aarch64"/>
+      <zipfileset src="${lib.native}/freebsd-ppc64le.jar"
+                  includes="*jnidispatch*"
+                  prefix="com/sun/jna/freebsd-ppc64le"/>
+      <zipfileset src="${lib.native}/freebsd-ppc64.jar"
+                  includes="*jnidispatch*"
+                  prefix="com/sun/jna/freebsd-ppc64"/>
       <zipfileset src="${lib.native}/openbsd-x86.jar"
                   includes="*jnidispatch*"
                   prefix="com/sun/jna/openbsd-x86"/>
@@ -725,6 +735,8 @@ osname=macosx;processor=aarch64
     <copy file="${lib.native}/out-of-date.jar" tofile="${lib.native}/freebsd-x86.jar" overwrite="true"/>
     <copy file="${lib.native}/out-of-date.jar" tofile="${lib.native}/freebsd-x86-64.jar" overwrite="true"/>
     <copy file="${lib.native}/out-of-date.jar" tofile="${lib.native}/freebsd-aarch64.jar" overwrite="true"/>
+    <copy file="${lib.native}/out-of-date.jar" tofile="${lib.native}/freebsd-ppc64le.jar" overwrite="true"/>
+    <copy file="${lib.native}/out-of-date.jar" tofile="${lib.native}/freebsd-ppc64.jar" overwrite="true"/>
     <copy file="${lib.native}/out-of-date.jar" tofile="${lib.native}/openbsd-x86.jar" overwrite="true"/>
     <copy file="${lib.native}/out-of-date.jar" tofile="${lib.native}/openbsd-x86-64.jar" overwrite="true"/>
     <copy file="${lib.native}/out-of-date.jar" tofile="${lib.native}/sunos-x86.jar" overwrite="true"/>
@@ -1223,6 +1235,10 @@ cd ..
       <propertyref prefix="java.awt.headless"/>
     </propertyset>
     <junit fork="${test.fork}" forkmode="${test.forkmode}" failureproperty="testfailure" tempdir="${build}">
+      <!-- let JVM ignore unknown flags -->
+      <jvmarg value="-XX:+IgnoreUnrecognizedVMOptions" />
+      <!-- enable JNI on JDK 24+ -->
+      <jvmarg value="--enable-native-access=ALL-UNNAMED" />
       <jvmarg if:set="test.jdwp" value="${test.jdwp}" />
       <!-- optionally run headless -->
       <syspropertyset refid="headless"/>
@@ -1293,10 +1309,8 @@ cd ..
       <path refid="compile.path"/>
       <pathelement location="${classes}"/>
     </path>
-    <property name="header"
-              value="<b>JNA API</><font size="-1"> ${jna.version}</font>"/>
-    <property name="footer"
-              value="<center><i>${copyright}</i></center>"/>
+    <property name="header" value="JNA API - ${jna.version}"/>
+    <property name="footer" value="${copyright}"/>
 
     <mkdir dir="${javadoc}"/>
     <condition property="javadoc.opts" value="-Xdoclint:none" else="">
@@ -1305,6 +1319,7 @@ cd ..
     <javadoc package="true"
              windowtitle="JNA API"
              encoding="UTF-8"
+             locale="en_US"
              sourcepathref="javadoc.src.path"
              classpathref="javadoc.compile.path"
              maxmemory="256m"
@@ -1316,7 +1331,6 @@ cd ..
       <doctitle>JNA API Documentation</doctitle>
       <header>${header}</header>
       <bottom>${footer}</bottom>
-      <link href="http://download.oracle.com/javase/${javac.release}/docs/api/"/>
 
       <packageset dir="${src}" defaultexcludes="yes">
         <patternset>
@@ -1334,7 +1348,16 @@ cd ..
       <group title="Platform Specific" packages="com.sun.jna.platform.*"/>
 
       <arg value="-notimestamp"/>
+      <!-- force locale to be "en_US", as Javadoc tool ignores locale parameter for some texts -->
+      <arg line="-J-Duser.language=en -J-Duser.country=US"/>
     </javadoc>
+    <!--
+    Create an empty resources/fonts/dejavu.css - the file is reference by default
+    javadoc output, yet not provided by it. People seem to be irritated by the
+    generated 404, so provide an empty file.
+    -->
+    <mkdir dir="${javadoc}/resources/fonts/" />
+    <echo file="${javadoc}/resources/fonts/dejavu.css">/* Intentionally left empty */</echo>
     <jar jarfile="${platform-javadoc-jar}" createUnicodeExtraFields="never" encoding="UTF-8">
       <fileset dir="${javadoc}" />
     </jar>
@@ -1491,11 +1514,14 @@ cd ..
   <property name="version-maven-gpg-plugin" value="1.4"/>
 
   <target name="stage" depends="dist" description="deploy release version to Maven staging repository">
+    <delete dir="build/maven-artifacts" />
+    <delete file="build/maven-artifacts.zip" />
+    <mkdir dir="build/maven-artifacts" />
+    <makeurl property="maven-artifacts" file="build/maven-artifacts" />
     <!-- sign and deploy the jna,  artifact -->
     <exec executable="mvn" searchpath="true" failonerror="true" failifexecutionfails="true" logError="true">
       <arg value="org.apache.maven.plugins:maven-gpg-plugin:${version-maven-gpg-plugin}:sign-and-deploy-file"/>
-      <arg value="-Durl=${maven-staging-repository-url}"/>
-      <arg value="-DrepositoryId=${maven-staging-repository-id}"/>
+      <arg value="-Durl=${maven-artifacts}"/>
       <arg value="-DpomFile=${pom}"/>
       <arg value="-Dfile=${dist-jar}"/>
       <arg value="-Dfiles=${maven-sources-jar},${maven-javadoc-jar},${dist-aar}"/>
@@ -1507,8 +1533,7 @@ cd ..
     <!-- sign and deploy the platform artifact -->
     <exec executable="mvn" searchpath="true" failonerror="true" failifexecutionfails="true" logError="true">
       <arg value="org.apache.maven.plugins:maven-gpg-plugin:${version-maven-gpg-plugin}:sign-and-deploy-file"/>
-      <arg value="-Durl=${maven-staging-repository-url}"/>
-      <arg value="-DrepositoryId=${maven-staging-repository-id}"/>
+      <arg value="-Durl=${maven-artifacts}"/>
       <arg value="-DpomFile=${pom-platform}"/>
       <arg value="-Dfile=${platform-jar}"/>
       <arg value="-Dfiles=${platform-sources-jar},${platform-javadoc-jar}"/>
@@ -1520,8 +1545,7 @@ cd ..
     <!-- sign and deploy the jna,  artifact -->
     <exec executable="mvn" searchpath="true" failonerror="true" failifexecutionfails="true" logError="true">
       <arg value="org.apache.maven.plugins:maven-gpg-plugin:${version-maven-gpg-plugin}:sign-and-deploy-file"/>
-      <arg value="-Durl=${maven-staging-repository-url}"/>
-      <arg value="-DrepositoryId=${maven-staging-repository-id}"/>
+      <arg value="-Durl=${maven-artifacts}"/>
       <arg value="-DpomFile=${pom-jpms}"/>
       <arg value="-Dfile=${dist-jar-jpms}"/>
       <arg value="-Dfiles=${maven-sources-jar},${maven-javadoc-jar}"/>
@@ -1533,8 +1557,7 @@ cd ..
     <!-- sign and deploy the platform artifact -->
     <exec executable="mvn" searchpath="true" failonerror="true" failifexecutionfails="true" logError="true">
       <arg value="org.apache.maven.plugins:maven-gpg-plugin:${version-maven-gpg-plugin}:sign-and-deploy-file"/>
-      <arg value="-Durl=${maven-staging-repository-url}"/>
-      <arg value="-DrepositoryId=${maven-staging-repository-id}"/>
+      <arg value="-Durl=${maven-artifacts}"/>
       <arg value="-DpomFile=${pom-platform-jpms}"/>
       <arg value="-Dfile=${platform-jpms-jar}"/>
       <arg value="-Dfiles=${platform-sources-jar},${platform-javadoc-jar}"/>
@@ -1542,6 +1565,9 @@ cd ..
       <arg value="-Dclassifiers=sources,javadoc"/>
       <arg value="-Dgpg.useagent=true"/>
     </exec>
+
+    <zip destfile="build/maven-artifacts.zip"
+         basedir="build/maven-artifacts"/>
   </target>
 
   <target name="checkstyle">


=====================================
common.xml
=====================================
@@ -1,16 +1,15 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <project name="JNA-Common" default="default" basedir=".">
     <property name="name" value="jna"/>
-    <property name="year" value="2018"/>
-    <property name="copyright"
-              value="Copyright &copy; 2007-${year} Timothy Wall. All Rights Reserved."/>
+    <property name="year" value="2025"/>
+    <property name="copyright" value="Copyright &copy; 2007-${year} Timothy Wall. All Rights Reserved."/>
     <property name="vendor" value="JNA Development Team"/>
     <buildnumber/>
 
     <!-- JNA library release version - android versionCode is derived from mjar/minor/revision -->
     <property name="jna.major" value="5"/>
-    <property name="jna.minor" value="15"/>
-    <property name="jna.revision" value="0"/>
+    <property name="jna.minor" value="18"/>
+    <property name="jna.revision" value="1"/>
     <property name="jna.build" value="0"/> <!--${build.number}-->
     <condition property="version.suffix" value="" else="-SNAPSHOT">
         <or>
@@ -23,7 +22,7 @@
     <!-- jnidispatch library release version -->
     <property name="jni.major" value="7"/>
     <property name="jni.minor" value="0"/>
-    <property name="jni.revision" value="2"/>
+    <property name="jni.revision" value="4"/>
     <property name="jni.build" value="0"/> <!--${build.number}-->
     <property name="jni.version" value="${jni.major}.${jni.minor}.${jni.revision}"/>
     <property name="jni.md5" value="5fb98531302accd485c534c452dd952a"/>


=====================================
contrib/platform/build.xml
=====================================
@@ -317,6 +317,10 @@ com.sun.jna.platform.wince;version="${osgi.version}";uses:="com.s
         <propertyref name="w32.ascii"/>
       </propertyset>
       <junit fork="${test.fork}" failureproperty="testfailure" tempdir="${build}">
+        <!-- let JVM ignore unknown flags -->
+        <jvmarg value="-XX:+IgnoreUnrecognizedVMOptions" />
+        <!-- enable JNI on JDK 24+ -->
+        <jvmarg value="--enable-native-access=ALL-UNNAMED" />
         <jvmarg if:set="test.jdwp" value="${test.jdwp}" />
         <!-- optionally run headless -->
         <syspropertyset refid="headless"/>


=====================================
contrib/platform/src/com/sun/jna/platform/mac/CoreFoundation.java
=====================================
@@ -1142,4 +1142,70 @@ public interface CoreFoundation extends Library {
      * @return The type identifier for the {@code CFString} opaque type.
      */
     CFTypeID CFStringGetTypeID();
+
+    /**
+     * The CFLocale opaque type provides support for obtaining available locales, obtaining localized locale names, and converting among locale data formats.
+     */
+    class CFLocale extends CFTypeRef {
+    }
+
+    /**
+     * Returns a copy of the logical locale for the current user.
+     * @return The logical locale for the current user that is formed from the settings for the current user’s
+     *         chosen system locale overlaid with any custom settings the user has specified in System Preferences.
+     *         May return a retained cached object, not a new object.
+     *         <p>
+     *         This reference must be released with {@link #CFRelease} to avoid leaking references.
+     */
+    CFLocale CFLocaleCopyCurrent();
+
+    /**
+     * CFDateFormatter objects format the textual representations of CFDate and CFAbsoluteTime objects, and convert textual representations of dates and times into CFDate and CFAbsoluteTime objects.
+     */
+    class CFDateFormatter extends CFTypeRef {
+    }
+
+    /**
+     * Enum of values used for {@link CFDateFormatterStyle} in {@link #CFDateFormatterCreate}.
+     * Use {@link CFDateFormatterStyle#index} for the expected integer value corresponding to the C-style enum.
+     */
+    enum CFDateFormatterStyle {
+        kCFDateFormatterNoStyle,
+        kCFDateFormatterShortStyle,
+        kCFDateFormatterMediumStyle,
+        kCFDateFormatterLongStyle,
+        kCFDateFormatterFullStyle;
+
+        /**
+         * Style for the type of {@link CFDateFormatterStyle} stored.
+         *
+         * @return a {@link CFIndex} representing the enum ordinal.
+         */
+        public CFIndex index() {
+            return new CFIndex(this.ordinal());
+        }
+    }
+
+    /**
+     * Creates a new CFDateFormatter object, localized to the given locale, which will format dates to the given date and time styles.
+     * @param allocator The allocator to use to allocate memory for the new object.
+     *                  Pass {@code null} or {@code kCFAllocatorDefault} to use the current default allocator.
+     * @param locale    The locale to use for localization.
+     *                  If {@code null} uses the default system locale.
+     *                  Use {@link #CFLocaleCopyCurrent()} to specify the locale of the current user.
+     * @param dateStyle The date style to use when formatting dates.
+     * @param timeStyle The time style to use when formatting times.
+     * @return A new date formatter, localized to the given locale, which will format dates to the given date and time styles.
+     *         Returns {@code null} if there was a problem creating the object.
+     *         <p>
+     *         This reference must be released with {@link #CFRelease} to avoid leaking references.
+     */
+    CFDateFormatter CFDateFormatterCreate(CFAllocatorRef allocator, CFLocale locale, CFIndex dateStyle, CFIndex timeStyle);
+
+    /**
+     * Returns a format string for the given date formatter object.
+     * @param formatter The date formatter to examine.
+     * @return The format string for {@code formatter}.
+     */
+    CFStringRef CFDateFormatterGetFormat(CFDateFormatter formatter);
 }


=====================================
contrib/platform/src/com/sun/jna/platform/unix/solaris/Kstat2.java
=====================================
@@ -272,10 +272,10 @@ public interface Kstat2 extends Library {
          *         {@link Kstat2Map} is returned.
          *         <p>
          *         If the value is of type {@link Kstat2#KSTAT2_NVVT_INT}, a
-         *         {@link long} is returned.
+         *         {@code long} is returned.
          *         <p>
          *         If the value is of type {@link Kstat2#KSTAT2_NVVT_INTS}, an array of
-         *         {@link long} is returned.
+         *         {@code long} is returned.
          *         <p>
          *         If the value is of type {@link Kstat2#KSTAT2_NVVT_STR}, a
          *         {@link String} is returned.


=====================================
contrib/platform/src/com/sun/jna/platform/win32/WinNT.java
=====================================
@@ -4420,4 +4420,6 @@ public interface WinNT extends WinError, WinDef, WinBase, BaseTSD {
     class TOKEN_ELEVATION extends Structure {
         public int TokenIsElevated;
     }
+
+    Guid.GUID GUID_CONSOLE_DISPLAY_STATE = new Guid.GUID("6FE69556-704A-47A0-8F24-C28D936FDA47");
 }


=====================================
contrib/platform/src/com/sun/jna/platform/win32/WinUser.java
=====================================
@@ -30,7 +30,6 @@ import com.sun.jna.Structure;
 import com.sun.jna.Structure.FieldOrder;
 import com.sun.jna.Union;
 import com.sun.jna.platform.win32.BaseTSD.ULONG_PTR;
-import com.sun.jna.platform.win32.WinDef.HKL;
 import com.sun.jna.platform.win32.WinNT.HANDLE;
 import com.sun.jna.win32.StdCallLibrary.StdCallCallback;
 import com.sun.jna.win32.W32APITypeMapper;
@@ -2088,4 +2087,79 @@ public interface WinUser extends WinDef {
      * Bitmask for the RESERVED2 key modifier.
      */
     int MODIFIER_RESERVED2_MASK = 32;
+
+    class HPOWERNOTIFY extends PVOID {
+        public HPOWERNOTIFY() {
+        }
+
+        public HPOWERNOTIFY(Pointer pointer) {
+            super(pointer);
+        }
+    }
+
+    /**
+     * Registers the application to receive power setting notifications for the specific power setting event.
+     * @param hRecipient Handle indicating where the power setting notifications are to be sent.
+     *                   For interactive applications, the Flags parameter should be DEVICE_NOTIFY_WINDOW_HANDLE,
+     *                   and the hRecipient parameter should be a window handle.
+     *                   For services, the Flags parameter should be DEVICE_NOTIFY_SERVICE_HANDLE, and the hRecipient
+     *                   parameter should be a SERVICE_STATUS_HANDLE as returned from RegisterServiceCtrlHandlerEx.
+     * @param PowerSettingGuid The GUID of the power setting for which notifications are to be sent.
+     * @param Flags
+     *   <li>DEVICE_NOTIFY_WINDOW_HANDLE - Notifications are sent using WM_POWERBROADCAST messages
+     *   with a wParam parameter of PBT_POWERSETTINGCHANGE.
+     *   <li>DEVICE_NOTIFY_SERVICE_HANDLE - Notifications are sent to the HandlerEx callback function with a dwControl
+     *   parameter of SERVICE_CONTROL_POWEREVENT and a dwEventType of PBT_POWERSETTINGCHANGE.
+     * @return a notification handle for unregistering for power notifications. If the function fails, the return
+     * value is NULL. To get extended error information, call GetLastError.
+     */
+    HPOWERNOTIFY RegisterPowerSettingNotification(
+            /*[in]*/ HANDLE hRecipient,
+            /*[in]*/ Guid.GUID PowerSettingGuid,
+            /*[in]*/ int Flags);
+
+    /**
+     * Unregisters the power setting notification.
+     * @param Handle The handle returned from the RegisterPowerSettingNotification function.
+     * @return If the function succeeds, the return value is nonzero.
+     * If the function fails, the return value is zero. To get extended error information, call GetLastError.
+     */
+    BOOL UnregisterPowerSettingNotification(
+            /*[in]*/ HPOWERNOTIFY Handle
+    );
+
+    int WM_POWERBROADCAST = 0x0218;
+
+    int PBT_APMQUERYSUSPEND = 0x0000;
+    int PBT_APMQUERYSTANDBY = 0x0001;
+    int PBT_APMQUERYSUSPENDFAILED = 0x0002;
+    int PBT_APMQUERYSTANDBYFAILED = 0x0003;
+    int PBT_APMSUSPEND = 0x0004;
+    int PBT_APMSTANDBY = 0x0005;
+    int PBT_APMRESUMECRITICAL = 0x0006;
+    int PBT_APMRESUMESUSPEND = 0x0007;
+    int PBT_APMRESUMESTANDBY = 0x0008;
+    int PBT_APMBATTERYLOW = 0x0009;
+    int PBT_APMPOWERSTATUSCHANGE = 0x000A;
+    int PBT_APMOEMEVENT = 0x000B;
+    int PBT_APMRESUMEAUTOMATIC = 0x0012;
+    int PBT_POWERSETTINGCHANGE = 0x8013;
+
+    @FieldOrder({"PowerSetting", "DataLength", "Data"})
+    class POWERBROADCAST_SETTING extends Structure {
+        public Guid.GUID PowerSetting;
+        public int DataLength;
+        public byte Data[] = new byte[1];
+
+        public POWERBROADCAST_SETTING(Pointer p) {
+            super(p);
+            read();
+        }
+
+        @Override
+        public final void read() {
+            Data = new byte[getPointer().getInt(fieldOffset("DataLength"))];
+            super.read();
+        }
+    }
 }
\ No newline at end of file


=====================================
contrib/platform/test/com/sun/jna/platform/linux/UdevTest.java
=====================================
@@ -29,6 +29,8 @@ import com.sun.jna.platform.linux.Udev.UdevContext;
 import com.sun.jna.platform.linux.Udev.UdevDevice;
 import com.sun.jna.platform.linux.Udev.UdevEnumerate;
 import com.sun.jna.platform.linux.Udev.UdevListEntry;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 import junit.framework.TestCase;
 
@@ -37,6 +39,8 @@ import junit.framework.TestCase;
  */
 public class UdevTest extends TestCase {
 
+    private static final Pattern SCSI_DISK_PATTERN = Pattern.compile(".*/sd[a-z](\\d+)$");
+
     @Test
     public void testEnumerateDevices() {
         // Start with the context object
@@ -74,7 +78,10 @@ public class UdevTest extends TestCase {
                                     // No additional reference is acquired from getParent
                                     if (parent != null && parent2 != null) {
                                         // Devnode should match same parent without restricting to block and disk
-                                        assertEquals("Partition parent should match with and without filter",
+                                        assertEquals(String.format(
+                                                "Partition parent should match with and without filter (%s)",
+                                                devnode
+                                                ),
                                                 parent.getDevnode(), parent2.getDevnode());
                                         // Save the size and major
                                         parentSize = parent.getSysattrValue("size");
@@ -82,21 +89,29 @@ public class UdevTest extends TestCase {
                                     }
                                 }
                                 String size = device.getSysattrValue("size");
-                                assertTrue("Size must be nonnegative", 0 <= Long.parseLong(size));
+                                assertTrue(String.format("Size must be nonnegative (%s)", devnode), 0 <= Long.parseLong(size));
                                 if (parentSize != null) {
-                                    assertTrue("Partition can't be bigger than its disk",
+                                    assertTrue(String.format("Partition can't be bigger than its disk (%s)", devnode),
                                             Long.parseLong(size) <= Long.parseLong(parentSize));
                                 }
                                 String major = device.getPropertyValue("MAJOR");
-                                assertTrue("Major value must be nonnegative", 0 <= Long.parseLong(major));
+                                assertTrue(String.format("Major value must be nonnegative (%s)", devnode), 0 <= Long.parseLong(major));
                                 if (parentMajor != null) {
-                                    assertEquals("Partition and its parent disk should have same major number", major,
-                                            parentMajor);
+                                    // For scsi disks only the first 15 Partitions have the
+                                    // same major as their disk
+                                    Matcher scsiMatcher = SCSI_DISK_PATTERN.matcher(devnode);
+                                    boolean scsiDiskDynamicMinor = scsiMatcher.matches() && Integer.parseInt(scsiMatcher.group(1)) > 15;
+                                    if(! scsiDiskDynamicMinor) {
+                                        assertEquals(
+                                                String.format("Partition and its parent disk should have same major number (%s)", devnode),
+                                                major, parentMajor
+                                        );
+                                    }
                                 }
-                                assertEquals("DevType mismatch", devType, device.getDevtype());
-                                assertEquals("Subsystem mismatch", "block", device.getSubsystem());
-                                assertEquals("Syspath mismatch", syspath, device.getSyspath());
-                                assertTrue("Syspath should end with name", syspath.endsWith(device.getSysname()));
+                                assertEquals(String.format("DevType mismatch (%s)", devnode), devType, device.getDevtype());
+                                assertEquals(String.format("Subsystem mismatch (%s)", devnode), "block", device.getSubsystem());
+                                assertEquals(String.format("Syspath mismatch (%s)", devnode), syspath, device.getSyspath());
+                                assertTrue(String.format("Syspath should end with name (%s)", devnode), syspath.endsWith(device.getSysname()));
                             }
                         } finally {
                             // Release the reference and iterate to the next device


=====================================
contrib/platform/test/com/sun/jna/platform/mac/CoreFoundationTest.java
=====================================
@@ -39,6 +39,7 @@ import java.util.Arrays;
 import java.util.List;
 import java.util.Random;
 
+import com.sun.jna.platform.mac.CoreFoundation.CFDateFormatterStyle;
 import com.sun.jna.platform.mac.CoreFoundation.CFDictionaryRef;
 import org.junit.Assert;
 import org.junit.Test;
@@ -49,7 +50,9 @@ import com.sun.jna.Pointer;
 import com.sun.jna.platform.mac.CoreFoundation.CFAllocatorRef;
 import com.sun.jna.platform.mac.CoreFoundation.CFArrayRef;
 import com.sun.jna.platform.mac.CoreFoundation.CFDataRef;
+import com.sun.jna.platform.mac.CoreFoundation.CFDateFormatter;
 import com.sun.jna.platform.mac.CoreFoundation.CFIndex;
+import com.sun.jna.platform.mac.CoreFoundation.CFLocale;
 import com.sun.jna.platform.mac.CoreFoundation.CFMutableDictionaryRef;
 import com.sun.jna.platform.mac.CoreFoundation.CFNumberRef;
 import com.sun.jna.platform.mac.CoreFoundation.CFNumberType;
@@ -380,4 +383,29 @@ public class CoreFoundationTest {
         CF.CFRelease(s1_the_same);
         CF.CFRelease(s2);
     }
+
+    @Test
+    public void testLocaleFormat() {
+        CFIndex style = CFDateFormatterStyle.kCFDateFormatterNoStyle.index();
+        assertEquals("", getLocaleDateTimeFormat(style));
+        style = CFDateFormatterStyle.kCFDateFormatterShortStyle.index();
+        assertTrue(getLocaleDateTimeFormat(style).contains("y"));
+    }
+
+    private static String getLocaleDateTimeFormat(CFIndex style) {
+        CFLocale locale = CF.CFLocaleCopyCurrent();
+        try {
+            CFDateFormatter formatter = CF.CFDateFormatterCreate(null, locale, style, style);
+            assertNotNull(formatter);
+            try {
+                CFStringRef format = CF.CFDateFormatterGetFormat(formatter);
+                assertNotNull(format);
+                return format.stringValue();
+            } finally {
+                CF.CFRelease(formatter);
+            }
+        } finally {
+            CF.CFRelease(locale);
+        }
+    }
 }


=====================================
contrib/platform/test/com/sun/jna/platform/win32/User32Test.java
=====================================
@@ -596,4 +596,12 @@ public class User32Test extends AbstractWin32TestSupport {
         // which is in an undefined state at test execution and may change arbitrarily
         // during the test.
     }
+
+    @Test
+    public void testRegisterPowerSettingNotification() {
+        WinUser.HPOWERNOTIFY hpowernotify = INSTANCE.RegisterPowerSettingNotification(
+                new HWND(), WinNT.GUID_CONSOLE_DISPLAY_STATE, User32.DEVICE_NOTIFY_WINDOW_HANDLE);
+        assertNotNull(hpowernotify);
+        assertNotEquals(0, INSTANCE.UnregisterPowerSettingNotification(hpowernotify));
+    }
 }


=====================================
native/Makefile
=====================================
@@ -89,6 +89,7 @@ LD=$(CC)
 LIBS=
 # Default to Sun recommendations for JNI compilation
 COPT=-O2 -fno-omit-frame-pointer -fno-strict-aliasing
+COPT+=-Wno-implicit-function-declaration
 CASM=-S
 ifeq ($(DEBUG),true)
 CDEBUG=-g
@@ -175,12 +176,12 @@ CPP=$(PREFIX)cpp
 LD=$(CC)
 RANLIB=$(PREFIX)ranlib
 STRIP=$(PREFIX)strip -x
-CDEFINES=-DFFI_STATIC_BUILD -DNO_JAWT -DNO_WEAK_GLOBALS -DFFI_MMAP_EXEC_WRIT=1 -DFFI_MMAP_EXEC_SELINUX=0
+CDEFINES=-DFFI_STATIC_BUILD -DNO_JAWT -DNO_WEAK_GLOBALS -DFFI_MMAP_EXEC_WRIT=1 -DFFI_MMAP_EXEC_SELINUX=0 -Dmalloc_getpagesize='getpagesize()'
 COPT+=-fpic -ffunction-sections -funwind-tables -fno-short-enums
 JAVA_INCLUDES=
 CINCLUDES+=-I"$(NDK_PLATFORM)/arch-$(AARCH)/usr/include" # -I/usr/include
 LIBS=-nostdlib -L"$(NDK_PLATFORM)/arch-$(AARCH)$(ALIBDIR)/" -lgcc -lc -ldl -lm
-LDFLAGS+=-Wl,-shared,-Bsymbolic -Wl,--build-id=sha1
+LDFLAGS+=-Wl,-shared,-Bsymbolic -Wl,--build-id=sha1 -Wl,-z,max-page-size=16384 -Wl,-z,common-page-size=16384
 FFI_ENV=CPP="$(CPP)" CC="$(CC)" CFLAGS="$(COPT) $(CDEBUG) $(CINCLUDES)" CPPFLAGS="$(CDEFINES) $(CINCLUDES)" LIBS="$(LIBS)" RANLIB="$(RANLIB)"
 FFI_CONFIG=--enable-static --disable-shared --with-pic=yes --host=$(HOST)
 endif


=====================================
src/com/sun/jna/Platform.java
=====================================
@@ -246,6 +246,10 @@ public final class Platform {
         return ARCH.startsWith("loongarch");
     }
 
+    public static final boolean isRISCV() {
+        return ARCH.startsWith("riscv");
+    }
+
     static String getCanonicalArchitecture(String arch, int platform) {
         arch = arch.toLowerCase().trim();
         if ("powerpc".equals(arch)) {


=====================================
src/com/sun/jna/Structure.java
=====================================
@@ -48,6 +48,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.WeakHashMap;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
@@ -155,8 +156,11 @@ public abstract class Structure {
     //public static final int ALIGN_8 = 6;
 
     protected static final int CALCULATE_SIZE = -1;
+    static final ReentrantReadWriteLock cacheStructureLock = new ReentrantReadWriteLock();
     static final Map<Class<?>, LayoutInfo> layoutInfo = new WeakHashMap<>();
     static final Map<Class<?>, List<String>> fieldOrder = new WeakHashMap<>();
+    static final Map<Class<?>, List<Field>> fieldList = new WeakHashMap<>();
+    static final Map<Class<?>, Boolean> validationMap = new WeakHashMap<>();
 
     // This field is accessed by native code
     private Pointer memory;
@@ -1015,22 +1019,43 @@ public abstract class Structure {
      * this {@link Structure} class.
      */
     protected List<Field> getFieldList() {
-        List<Field> flist = new ArrayList<>();
-        for (Class<?> cls = getClass();
-             !cls.equals(Structure.class);
-             cls = cls.getSuperclass()) {
-            List<Field> classFields = new ArrayList<>();
-            Field[] fields = cls.getDeclaredFields();
-            for (int i=0;i < fields.length;i++) {
-                int modifiers = fields[i].getModifiers();
-                if (Modifier.isStatic(modifiers) || !Modifier.isPublic(modifiers)) {
-                    continue;
-                }
-                classFields.add(fields[i]);
+        Class<?> clazz = getClass();
+        // Try to read the value under the read lock
+        cacheStructureLock.readLock().lock();
+        try {
+            List<Field> fields = fieldList.get(clazz);
+            if (fields != null) {
+                return fields; // Return the cached result if found
             }
-            flist.addAll(0, classFields);
+        } finally {
+            cacheStructureLock.readLock().unlock();
+        }
+
+        // If not found, compute the value under the write lock
+        cacheStructureLock.writeLock().lock();
+        try {
+            // Double-check if another thread has computed the value before we do
+            return fieldList.computeIfAbsent(clazz, (c) -> {
+                List<Field> flist = new ArrayList<>();
+                List<Field> classFields = new ArrayList<>();
+                for (Class<?> cls = clazz;
+                     !cls.equals(Structure.class);
+                     cls = cls.getSuperclass()) {
+                    for (Field field : cls.getDeclaredFields()) {
+                        int modifiers = field.getModifiers();
+                        if (Modifier.isStatic(modifiers) || !Modifier.isPublic(modifiers)) {
+                            continue;
+                        }
+                        classFields.add(field);
+                    }
+                    flist.addAll(0, classFields);
+                    classFields.clear();
+                }
+                return flist;
+            });
+        } finally {
+            cacheStructureLock.writeLock().unlock();
         }
-        return flist;
     }
 
     /** Cache field order per-class.
@@ -1038,13 +1063,24 @@ public abstract class Structure {
      */
     private List<String> fieldOrder() {
         Class<?> clazz = getClass();
-        synchronized(fieldOrder) {
-            List<String> list = fieldOrder.get(clazz);
-            if (list == null) {
-                list = getFieldOrder();
-                fieldOrder.put(clazz, list);
+        // Try to read the value under the read lock
+        cacheStructureLock.readLock().lock();
+        try {
+            List<String> order = fieldOrder.get(clazz);
+            if (order != null) {
+                return order; // Return the cached result if found
             }
-            return list;
+        } finally {
+            cacheStructureLock.readLock().unlock();
+        }
+
+        // If not found, compute the value under the write lock
+        cacheStructureLock.writeLock().lock();
+        try {
+            // Double-check if another thread has computed the value before we do (see JavaDoc)
+            return fieldOrder.computeIfAbsent(clazz, (c) -> getFieldOrder());
+        } finally {
+            cacheStructureLock.writeLock().unlock();
         }
     }
 
@@ -1089,7 +1125,7 @@ public abstract class Structure {
         and can't be generated automatically.
     **/
     protected List<Field> getFields(boolean force) {
-        List<Field> flist = getFieldList();
+        List<Field> flist = new ArrayList<>(getFieldList());
         Set<String> names = new HashSet<>();
         for (Field f : flist) {
             names.add(f.getName());
@@ -1159,8 +1195,11 @@ public abstract class Structure {
      */
     static <T extends Structure> int size(Class<T> type, T value) {
         LayoutInfo info;
-        synchronized(layoutInfo) {
+        cacheStructureLock.readLock().lock();
+        try {
             info = layoutInfo.get(type);
+        } finally {
+            cacheStructureLock.readLock().unlock();
         }
         int sz = (info != null && !info.variable) ? info.size : CALCULATE_SIZE;
         if (sz == CALCULATE_SIZE) {
@@ -1183,8 +1222,11 @@ public abstract class Structure {
         int size = CALCULATE_SIZE;
         Class<?> clazz = getClass();
         LayoutInfo info;
-        synchronized(layoutInfo) {
+        cacheStructureLock.readLock().lock();
+        try {
             info = layoutInfo.get(clazz);
+        } finally {
+            cacheStructureLock.readLock().unlock();
         }
         if (info == null
             || this.alignType != info.alignType
@@ -1196,7 +1238,8 @@ public abstract class Structure {
             this.structFields = info.fields;
 
             if (!info.variable) {
-                synchronized(layoutInfo) {
+                cacheStructureLock.readLock().lock();
+                try {
                     // If we've already cached it, only override layout if
                     // we're using non-default values for alignment and/or
                     // type mapper; this way we don't override the cache
@@ -1205,8 +1248,18 @@ public abstract class Structure {
                     if (!layoutInfo.containsKey(clazz)
                         || this.alignType != ALIGN_DEFAULT
                         || this.typeMapper != null) {
+                        // Must release read lock before acquiring write lock (see JavaDoc lock escalation example)
+                        cacheStructureLock.readLock().unlock();
+                        cacheStructureLock.writeLock().lock();
+
                         layoutInfo.put(clazz, info);
+
+                        // Downgrade by acquiring read lock before releasing write lock (again, see JavaDoc)
+                        cacheStructureLock.readLock().lock();
+                        cacheStructureLock.writeLock().unlock();;
                     }
+                } finally {
+                    cacheStructureLock.readLock().unlock();
                 }
             }
             size = info.size;
@@ -1250,9 +1303,28 @@ public abstract class Structure {
 
     /** ensure all fields are of valid type. */
     private void validateFields() {
-        List<Field> fields = getFieldList();
-        for (Field f : fields) {
-            validateField(f.getName(), f.getType());
+        // Try to read the value under the read lock
+        cacheStructureLock.readLock().lock();
+        try {
+            if (validationMap.containsKey(getClass())) {
+                return; // Return because this Structure has already been validated
+            }
+        } finally {
+            cacheStructureLock.readLock().unlock();
+        }
+
+        // If not found, perform validation and update the cache under the write lock
+        cacheStructureLock.writeLock().lock();
+        try {
+            // Double-check if another thread has computed the value before we do (see JavaDoc)
+            validationMap.computeIfAbsent(getClass(), (cls) -> {
+                for (Field f : getFieldList()) {
+                    validateField(f.getName(), f.getType());
+                }
+                return true;
+            });
+        } finally {
+            cacheStructureLock.writeLock().unlock();
         }
     }
 
@@ -2139,9 +2211,7 @@ public abstract class Structure {
         /** Obtain a pointer to the native FFI type descriptor for the given object. */
         static FFIType get(Object obj) {
             if (obj == null)
-                synchronized (typeInfoMap) {
-                    return getTypeInfo(Pointer.class, 0);
-                }
+                return getTypeInfo(Pointer.class, 0);
             if (obj instanceof Class)
                 return get(null, (Class<?>)obj);
             return get(obj, obj.getClass());
@@ -2155,13 +2225,14 @@ public abstract class Structure {
                     cls = nc.nativeType();
                 }
             }
-            synchronized(typeInfoMap) {
-                FFIType o = getTypeInfo(cls, cls.isArray() ? Array.getLength(obj) : 0);
-                if (o != null) {
-                    return o;
-                }
+            FFIType o = getTypeInfo(cls, cls.isArray() ? Array.getLength(obj) : 0);
+            if (o != null) {
+                return o;
+            }
+            cacheStructureLock.writeLock().lock();
+            try {
                 if ((Platform.HAS_BUFFERS && Buffer.class.isAssignableFrom(cls))
-                    || Callback.class.isAssignableFrom(cls)) {
+                        || Callback.class.isAssignableFrom(cls)) {
                     typeInfoMap.put(cls, typeInfoMap.get(Pointer.class));
                     return typeInfoMap.get(Pointer.class).get(0);
                 }
@@ -2171,30 +2242,42 @@ public abstract class Structure {
                         typeInfoMap.put(cls, typeInfoMap.get(Pointer.class));
                         return typeInfoMap.get(Pointer.class).get(0);
                     }
-                    FFIType type = new FFIType((Structure)obj);
+                    FFIType type = new FFIType((Structure) obj);
                     storeTypeInfo(cls, type);
                     return type;
                 }
-                if (NativeMapped.class.isAssignableFrom(cls)) {
-                    NativeMappedConverter c = NativeMappedConverter.getInstance(cls);
-                    return get(c.toNative(obj, new ToNativeContext()), c.nativeType());
-                }
-                if (cls.isArray()) {
-                    FFIType type = new FFIType(obj, cls);
-                    // Store it in the map to prevent premature GC of type info
-                    storeTypeInfo(cls, Array.getLength(obj), type);
-                    return type;
-                }
-                throw new IllegalArgumentException("Unsupported type " + cls);
             }
+            finally {
+                cacheStructureLock.writeLock().unlock();
+            }
+
+            if (NativeMapped.class.isAssignableFrom(cls)) {
+                NativeMappedConverter c = NativeMappedConverter.getInstance(cls);
+                return get(c.toNative(obj, new ToNativeContext()), c.nativeType());
+            }
+
+            if (cls.isArray()) {
+                FFIType type = new FFIType(obj, cls);
+                // Store it in the map to prevent premature GC of type info
+                storeTypeInfo(cls, Array.getLength(obj), type);
+                return type;
+            }
+
+            throw new IllegalArgumentException("Unsupported type " + cls);
         }
 
         private static FFIType getTypeInfo(Class clazz, int elementCount) {
-            Map<Integer,FFIType> typeMap = typeInfoMap.get(clazz);
-            if(typeMap != null) {
-                return typeMap.get(elementCount);
-            } else {
-                return null;
+            cacheStructureLock.readLock().lock();
+            try {
+                Map<Integer, FFIType> typeMap = typeInfoMap.get(clazz);
+                if (typeMap != null) {
+                    return typeMap.get(elementCount);
+                } else {
+                    return null;
+                }
+            }
+            finally {
+                cacheStructureLock.readLock().unlock();
             }
         }
 
@@ -2203,14 +2286,14 @@ public abstract class Structure {
         }
 
         private static void storeTypeInfo(Class clazz, int elementCount, FFIType type) {
-            synchronized (typeInfoMap) {
-                Map<Integer,FFIType> typeMap = typeInfoMap.get(clazz);
-                if(typeMap == null) {
-                    typeMap = new HashMap<>();
-                    typeInfoMap.put(clazz, typeMap);
-                }
+            cacheStructureLock.writeLock().lock();
+            try {
+                Map<Integer, FFIType> typeMap = typeInfoMap.computeIfAbsent(clazz, k -> new HashMap<>());
                 typeMap.put(elementCount, type);
             }
+            finally {
+                cacheStructureLock.writeLock().unlock();
+            }
         }
     }
 


=====================================
src/com/sun/jna/overview.html
=====================================
@@ -29,6 +29,9 @@ additional JNI or native code.
 <h2>Table of Contents</h2>
 <ul>
 <li><a href="#loading">Loading JNA</a>
+  <ul>
+  <li><a href="#loading-jdk24">Special considerations for JDK24+</a>
+  </ul>
 <li><a href="#library-mapping">Library Mapping</a>
 <li><a href="#function-mapping">Function Mapping</a>
 <li><a href="#marshalling">Type Mapping</a>
@@ -81,6 +84,53 @@ or if your system must store different versions of the JNA shared
 library (e.g. for different architectures) in the same directory.
 <p/>
 
+<a href=#navbar_top>Top</a>
+<a name="loading-jdk24"></a>
+<h3>Special considerations for JDK24+</h3>
+The JDK moves to "safe by default" or "Integrity by Default" settings. Settings
+that might compromise the integrity provided by the JVM are off by default.
+Since JDK 24 this also affects the usage of Java Native Interface (JNI). This
+is part of the foundation JNA is built upon. For JDK 24 this is a warning, in
+the future JNI will be restricted to explicitly enabled modules.
+<p/>
+To fix the warnings and prepare for the future, the applications using JNA need
+to be modified. The java launcher will need to be instructed to allow JNI for
+the module JNA was loaded from. In the most basic case JNA is loaded from the
+classpath. For example, the built in mini-check of JNA can be invoked as:
+
+<blockquote><code><pre>
+java -jar jna.jar
+</blockquote></code></pre>
+
+This will need to be modified to:
+
+<blockquote><code><pre>
+java --enable-native-access=ALL-UNNAMED -jar jna.jar
+</blockquote></code></pre>
+
+If JNA is loaded from the modulepath
+
+<blockquote><code><pre>
+java -p jna-jpms.jar -m com.sun.jna
+</blockquote></code></pre>
+
+That will need to be modified to:
+
+<blockquote><code><pre>
+java --enable-native-access=com.sun.jna -p jna-jpms.jar -m com.sun.jna
+</blockquote></code></pre>
+
+For executable JARs the manifest attribute <code>Enable-Native-Access</code> can
+be set to the value <code>ALL-UNNAMED</code> to enable native access for this
+case.
+<p/>
+How these changes are applied to the concrete project is highly dependending on
+the setup of that project and thus no general advise can be presented here.
+<p/>
+More information can be found on the page describing <a
+href="https://openjdk.org/jeps/472" target="_blank">JEP 472: Prepare to Restrict
+the Use of JNI</a>
+<p/>
 <a href=#navbar_top>Top</a>
 <a name="library-mapping"></a>
 <h2>Library Mapping</h2>



View it on GitLab: https://salsa.debian.org/java-team/libjna-java/-/compare/4a7b045eff453c765f74d560adcf4e2123c9a1d3...61b94c2079d10813c6ca740075ea1b608f671730

-- 
View it on GitLab: https://salsa.debian.org/java-team/libjna-java/-/compare/4a7b045eff453c765f74d560adcf4e2123c9a1d3...61b94c2079d10813c6ca740075ea1b608f671730
You're receiving this email because of your account on salsa.debian.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-java-commits/attachments/20260315/207028e6/attachment.htm>


More information about the pkg-java-commits mailing list