[Git][java-team/libjna-java][master] 8 commits: New upstream version 5.16.0
Emmanuel Bourg (@ebourg)
gitlab at salsa.debian.org
Sun Mar 15 19:52:55 GMT 2026
Emmanuel Bourg pushed to branch master 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
- - - - -
74afe21d by Emmanuel Bourg at 2026-03-15T20:42:17+01:00
Update upstream source from tag 'upstream/5.18.1'
Update to upstream version '5.18.1'
with Debian dir bc43867b4b025f5fd9eed19fedcaec35669e2e8b
- - - - -
24620a7f by Emmanuel Bourg at 2026-03-15T20:42:17+01:00
Refreshed the patches
- - - - -
aaad2719 by Emmanuel Bourg at 2026-03-15T20:42:32+01:00
Standards-Version updated to 4.7.3
- - - - -
e3e09670 by Emmanuel Bourg at 2026-03-15T20:45:11+01:00
Upload to unstable
- - - - -
25 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
- debian/changelog
- debian/control
- debian/patches/03-dynlink-and-cflags.patch
- debian/patches/04-load-native-code-from-fs.patch
- debian/patches/09-javadoc.patch
- debian/patches/10-disable-full-jar.patch
- debian/patches/18-build-directory-in-soname.patch
- debian/patches/19-asm-classpath.patch
- 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
---
-[](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)
+[](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
------------
-[](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)
+[](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 © 2007-${year} Timothy Wall. All Rights Reserved."/>
+ <property name="year" value="2025"/>
+ <property name="copyright" value="Copyright © 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));
+ }
}
=====================================
debian/changelog
=====================================
@@ -1,3 +1,12 @@
+libjna-java (5.18.1-1) unstable; urgency=medium
+
+ * Team upload.
+ * New upstream release
+ - Refreshed the patches
+ * Standards-Version updated to 4.7.3
+
+ -- Emmanuel Bourg <ebourg at apache.org> Sun, 15 Mar 2026 20:45:04 +0100
+
libjna-java (5.15.0-1) unstable; urgency=medium
* Team upload.
=====================================
debian/control
=====================================
@@ -18,7 +18,7 @@ Build-Depends:
libxt-dev,
maven-repo-helper (>= 1.5~),
pkgconf
-Standards-Version: 4.7.0
+Standards-Version: 4.7.3
Rules-Requires-Root: no
Vcs-Git: https://salsa.debian.org/java-team/libjna-java.git
Vcs-Browser: https://salsa.debian.org/java-team/libjna-java
=====================================
debian/patches/03-dynlink-and-cflags.patch
=====================================
@@ -3,7 +3,7 @@ Description: dynlink and cflags
--- a/build.xml
+++ b/build.xml
-@@ -1006,6 +1006,10 @@
+@@ -1018,6 +1018,10 @@
<arg value="JNA_JNI_VERSION=${jni.version}"/>
<arg value="CHECKSUM=${jni.md5}"/>
</exec>
@@ -14,7 +14,7 @@ Description: dynlink and cflags
<mkdir dir="${classes}/${native.path}"/>
<copy todir="${classes}/${native.path}">
<fileset dir="${build.native}"
-@@ -1017,18 +1021,6 @@
+@@ -1029,18 +1033,6 @@
<fileset dir="${build.native}"
includes="jnidispatch.dll,libjnidispatch.*"/>
</copy>
=====================================
debian/patches/04-load-native-code-from-fs.patch
=====================================
@@ -57,7 +57,7 @@ Author: Jan Dittberner <jandd at debian.org>
*/
--- a/src/com/sun/jna/Platform.java
+++ b/src/com/sun/jna/Platform.java
-@@ -269,8 +269,12 @@
+@@ -273,8 +273,12 @@
arch = "ppc64le";
}
// Map arm to armel if the binary is running as softfloat build
@@ -72,7 +72,7 @@ Author: Jan Dittberner <jandd at debian.org>
}
return arch;
-@@ -362,4 +366,30 @@
+@@ -366,4 +370,30 @@
}
return osPrefix;
}
=====================================
debian/patches/09-javadoc.patch
=====================================
@@ -2,11 +2,10 @@ Link javadoc to the default-jdk javadoc.
--- a/build.xml
+++ b/build.xml
-@@ -1308,7 +1308,7 @@
+@@ -1323,6 +1323,7 @@
<doctitle>JNA API Documentation</doctitle>
<header>${header}</header>
<bottom>${footer}</bottom>
-- <link href="http://download.oracle.com/javase/${javac.release}/docs/api/"/>
+ <link href="/usr/share/doc/default-jdk-doc/api/"/>
<packageset dir="${src}" defaultexcludes="yes">
=====================================
debian/patches/10-disable-full-jar.patch
=====================================
@@ -3,7 +3,7 @@ Author: Emmanuel Bourg <ebourg at apache.org>
Forwarded: not-needed
--- a/build.xml
+++ b/build.xml
-@@ -327,6 +327,7 @@
+@@ -325,6 +325,7 @@
<!-- Note that no terminal "*" is included in this list,
which will force failure on unsupported platforms.
-->
@@ -11,7 +11,7 @@ Forwarded: not-needed
<attribute name="Bundle-NativeCode"
value="
com/sun/jna/win32-x86/jnidispatch.dll;
-@@ -415,6 +416,7 @@
+@@ -417,6 +418,7 @@
com/sun/jna/darwin-aarch64/libjnidispatch.jnilib;
osname=macosx;processor=aarch64
"/>
@@ -19,7 +19,7 @@ Forwarded: not-needed
</manifest>
<manifest file="@{target}" mode="update" if:true="@{module-info}">
<attribute name="Multi-Release" value="true"/>
-@@ -445,6 +447,7 @@
+@@ -449,6 +451,7 @@
<fileset dir="${classes}" excludes="${jar.omitted}">
<patternset refid="jar-compiled"/>
</fileset>
@@ -27,7 +27,7 @@ Forwarded: not-needed
<zipfileset src="${lib.native}/win32-x86.jar"
includes="*jnidispatch*"
prefix="com/sun/jna/win32-x86"/>
-@@ -550,6 +553,7 @@
+@@ -560,6 +563,7 @@
<zipfileset src="${lib.native}/w32ce-arm.jar"
includes="*jnidispatch*"
prefix="com/sun/jna/w32ce-arm"/>
=====================================
debian/patches/18-build-directory-in-soname.patch
=====================================
@@ -4,7 +4,7 @@ Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=956178
--- a/native/Makefile
+++ b/native/Makefile
-@@ -284,10 +284,10 @@
+@@ -285,10 +285,10 @@
PCFLAGS+=-fPIC
CDEFINES+=-DHAVE_PROTECTION
ifeq ($(DYNAMIC_LIBFFI),true)
=====================================
debian/patches/19-asm-classpath.patch
=====================================
@@ -1,6 +1,6 @@
--- a/build.xml
+++ b/build.xml
-@@ -104,9 +104,9 @@
+@@ -102,9 +102,9 @@
<target name="-prepare-anttools">
<subant antfile="build-ant-tools.xml" buildpath="${basedir}"></subant>
=====================================
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/457998b3ab5858a4fc2f6b6188e668290f3dfd09...e3e09670b08dc5cbd7d4fc9ded8b3ef407873851
--
View it on GitLab: https://salsa.debian.org/java-team/libjna-java/-/compare/457998b3ab5858a4fc2f6b6188e668290f3dfd09...e3e09670b08dc5cbd7d4fc9ded8b3ef407873851
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/d5e31c19/attachment.htm>
More information about the pkg-java-commits
mailing list