From bd05b75ea922ca319de9078f1b8b6af8988527d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Bl=C3=A4sing?= Date: Thu, 4 Jul 2024 20:58:36 +0200 Subject: [PATCH] Add Native#getNativeLibrary to get access to library wrapped by Native#load or Native#register --- CHANGES.md | 1 + src/com/sun/jna/Native.java | 46 +++++++++ .../sun/jna/NativeGetNativeLibraryTest.java | 94 +++++++++++++++++++ 3 files changed, 141 insertions(+) create mode 100644 test/com/sun/jna/NativeGetNativeLibraryTest.java diff --git a/CHANGES.md b/CHANGES.md index 0d02adc97..17cab60ed 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -11,6 +11,7 @@ Features * [#1593](https://github.com/java-native-access/jna/pull/1593): Add support for DragonFly BSD x86-64 - [@liweitianux](https://github.com/liweitianux). * [#1595](https://github.com/java-native-access/jna/pull/1595): Add `IsProcessorFeaturePresent` to `c.s.j.p.win32.Kernel32` - [@dbwiddis](https://github.com/dbwiddis). * [#1602](https://github.com/java-native-access/jna/pull/1602): Add `XMoveWindow`, `XResizeWindow`, `XMoveResizeWindow`, `XRaiseWindow`, `XLowerWindow` X11 calls to `c.s.j.p.unix.X11` - [@vinceh121](https://github.com/vinceh121). +* [#1613](https://github.com/java-native-access/jna/issues/1613): Added static helper method `Native#getNativeLibrary' for getting the underlying NativeLibrary instance from a Library interface instance or from a "registered" class - [@matthiasblaesing](https://github.com/matthiasblaesing). Bug Fixes --------- diff --git a/src/com/sun/jna/Native.java b/src/com/sun/jna/Native.java index 7edeb05c5..5226b36dd 100644 --- a/src/com/sun/jna/Native.java +++ b/src/com/sun/jna/Native.java @@ -1918,6 +1918,52 @@ public static void register(Class cls, NativeLibrary lib) { } } + /** + * Get the {@link NativeLibrary} instance that is wrapped by the given + * {@link Library} interface instance. + * + * @param library the {@link Library} interface instance, which was created + * by the {@link Native#load Native.load()} method + * @return the wrapped {@link NativeLibrary} instance + */ + public static NativeLibrary getNativeLibrary(final Library library) { + if(library == null) { + throw new IllegalArgumentException("null passed to getNativeLibrary"); + } + if(! Proxy.isProxyClass(library.getClass())) { + throw new IllegalArgumentException("library object passed to getNativeLibrary in not a proxy"); + } + final InvocationHandler handler = Proxy.getInvocationHandler(library); + if (!(handler instanceof Library.Handler)) { + throw new IllegalArgumentException("Object is not a properly initialized Library interface instance"); + } + return ((Library.Handler) handler).getNativeLibrary(); + } + + /** + * Get the {@link NativeLibrary} instance to which the given "registered" + * class is bound. + * + * @param cls the "registered" class, which was previously registered via + * the {@link Native#register register()} method + * @return the {@link NativeLibrary} instance to which the "registered" + * class is bound + */ + public static NativeLibrary getNativeLibrary(final Class cls) { + if(cls == null) { + throw new IllegalArgumentException("null passed to getNativeLibrary"); + } + final Class mappedClass = findDirectMappedClass(cls); + synchronized(registeredClasses) { + final NativeLibrary nativeLibrary = registeredLibraries.get(mappedClass); + if (nativeLibrary == null) { + throw new IllegalArgumentException("Class " + cls.getName() + " is not currently registered"); + } else { + return nativeLibrary; + } + } + } + /* Take note of options used for a given library mapping, to facilitate * looking them up later. */ diff --git a/test/com/sun/jna/NativeGetNativeLibraryTest.java b/test/com/sun/jna/NativeGetNativeLibraryTest.java new file mode 100644 index 000000000..017625c0a --- /dev/null +++ b/test/com/sun/jna/NativeGetNativeLibraryTest.java @@ -0,0 +1,94 @@ +/* Copyright (c) 2024 Matthias Bläsing, All Rights Reserved + * + * The contents of this file is dual-licensed under 2 + * alternative Open Source/Free licenses: LGPL 2.1 or later and + * Apache License 2.0. (starting with JNA version 4.0.0). + * + * You can freely decide which license you want to apply to + * the project. + * + * You may obtain a copy of the LGPL License at: + * + * http://www.gnu.org/licenses/licenses.html + * + * A copy is also included in the downloadable source code package + * containing JNA, in file "LGPL2.1". + * + * You may obtain a copy of the Apache License at: + * + * http://www.apache.org/licenses/ + * + * A copy is also included in the downloadable source code package + * containing JNA, in file "AL2.0". + */ +package com.sun.jna; + +import java.util.Collections; +import junit.framework.TestCase; + +/** + * Check getNativeLibrary functions in Native + */ +public class NativeGetNativeLibraryTest extends TestCase { + + private NativeLibrary libUTF8; + private TestLib libUTF8Interface; + + @Override + protected void setUp() { + libUTF8 = NativeLibrary.getInstance("testlib", + Collections.singletonMap(Library.OPTION_STRING_ENCODING, "UTF-8")); + Native.register(TestLibUTF8.class, libUTF8); + libUTF8Interface = Native.load("testlib", TestLib.class, + Collections.singletonMap(Library.OPTION_STRING_ENCODING, "UTF-8")); + } + + public void testGetNativeLibraryInterface() { + NativeLibrary nl = Native.getNativeLibrary(libUTF8Interface); + assertTrue(nl instanceof NativeLibrary); + } + + public void testGetNativeLibraryDirect() { + NativeLibrary nl = Native.getNativeLibrary(TestLibUTF8.class); + assertTrue(nl instanceof NativeLibrary); + // This only makes sense for the direct case, as that directly wraps + // a supplied instance + assertEquals(libUTF8, nl); + } + + public void testGetNativeLibraryOnUnboundShouldFail() { + try { + Native.getNativeLibrary(new TestLib() { + @Override + public String returnStringArgument(Pointer input) { + return ""; + } + }); + assertTrue("Exception not thrown", false); + } catch (IllegalArgumentException ex) { + // This should be reached + } + } + + public void testGetNativeLibraryOnNullShouldFail() { + try { + Native.getNativeLibrary((Class) null); + assertTrue("Exception not thrown", false); + } catch (IllegalArgumentException ex) { + // This should be reached + } + } + + public static void main(java.lang.String[] argList) { + junit.textui.TestRunner.run(NativeGetNativeLibraryTest.class); + } + + private static class TestLibUTF8 implements Library { + native String returnStringArgument(Pointer input); + } + + private interface TestLib extends Library { + public String returnStringArgument(Pointer input); + } + +}