Using a NativeMapped type as struct member

74 views
Skip to first unread message

falco

unread,
May 10, 2021, 6:54:59 AM5/10/21
to Java Native Access
Hi all,

please tell me if the following is a legitimate bug or if I'm using JNA in unfortunate ways.
I'd like to use a struct and that struct should have a member of type NativeMapped on the Java side.

This is my reproducer within the JNA test suite, as patch:

diff --git a/native/testlib.c b/native/testlib.c
index 5ea8b605b..a775d1e35 100644
--- a/native/testlib.c
+++ b/native/testlib.c
@@ -112,7 +112,14 @@ struct CheckFieldAlignment {
   float floatField;
   double doubleField;
 };
+    
+struct MyStruct {
+    char *myString;
+};
 
+EXPORT void acceptMyStruct(struct MyStruct *it) {
+    printf("%s", it->myString);
+}
 static int _callCount;
 
 EXPORT int
diff --git a/test/com/sun/jna/ReturnTypesTest.java b/test/com/sun/jna/ReturnTypesTest.java
index d7b340cde..08c9105e9 100644
--- a/test/com/sun/jna/ReturnTypesTest.java
+++ b/test/com/sun/jna/ReturnTypesTest.java
@@ -130,6 +130,7 @@ public class ReturnTypesTest extends TestCase {
         Pointer[] returnPointerArgument(Pointer[] arg);
         String[] returnPointerArgument(String[] arg);
         WString[] returnPointerArgument(WString[] arg);
+        void acceptMyStruct(MyStruct ms);
     }
 
     TestLibrary lib;
@@ -225,6 +226,31 @@ public class ReturnTypesTest extends TestCase {
             setValue(value);
         }
     }
+    public static class MyStruct extends Structure {
+    public MyString myString;
+    }
+    public static class MyString implements NativeMapped {
+
+ @Override
+ public Object fromNative(Object nativeValue, FromNativeContext context) {
+ return new MyString();
+ }
+
+ @Override
+ public Object toNative() {
+ return new byte[] { (byte) 0xDEAD, (byte) 0xBEEF };
+ }
+
+ @Override
+ public Class<?> nativeType() {
+ return byte[].class;
+ }
+   
+    }
+    public void testInvokeNativeMappedBytes() {
+    lib.acceptMyStruct(new MyStruct());
+    }
+  
     public static class Custom implements NativeMapped {
         private int value;
         public Custom() { }

But then I get:

    [junit] Testcase: testInvokeNativeMappedBytes(com.sun.jna.ReturnTypesTest): Caused an ERROR
    [junit] Invalid Structure field in class com.sun.jna.ReturnTypesTest$MyStruct, field name 'myString' (class com.sun.jna.ReturnTypesTest$MyString): The type "com.sun.jna.ReturnTypesTest$MyString" is not supported: Native size for type "[B" is unknown
    [junit] java.lang.IllegalArgumentException: Invalid Structure field in class com.sun.jna.ReturnTypesTest$MyStruct, field name 'myString' (class com.sun.jna.ReturnTypesTest$MyString): The type "com.sun.jna.ReturnTypesTest$MyString" is not supported: Native size for type "[B" is unknown
    [junit] at com.sun.jna.Structure.validateField(Structure.java:1246)
    [junit] at com.sun.jna.Structure.validateFields(Structure.java:1255)
    [junit] at com.sun.jna.Structure.<init>(Structure.java:211)
    [junit] at com.sun.jna.Structure.<init>(Structure.java:204)
    [junit] at com.sun.jna.Structure.<init>(Structure.java:191)
    [junit] at com.sun.jna.Structure.<init>(Structure.java:183)
    [junit] at com.sun.jna.ReturnTypesTest$MyStruct.<init>(ReturnTypesTest.java:229)
    [junit] at com.sun.jna.ReturnTypesTest.testInvokeNativeMappedBytes(ReturnTypesTest.java:251)
    [junit] Caused by: java.lang.IllegalArgumentException: The type "com.sun.jna.ReturnTypesTest$MyString" is not supported: Native size for type "[B" is unknown
    [junit] at com.sun.jna.Native.getNativeSize(Native.java:1386)
    [junit] at com.sun.jna.Structure.getNativeSize(Structure.java:2284)
    [junit] at com.sun.jna.Structure.getNativeSize(Structure.java:2274)
    [junit] at com.sun.jna.Structure.validateField(Structure.java:1242)
    [junit]
    [junit]
    [junit] Test com.sun.jna.ReturnTypesTest FAILED

I would assume that JNA can deduce the size if it weren't for NativeMapped. JNA also does it when MyString is not part of a struct, but rather directly used as parameter. Why the difference?
Thanks for reading.

Matthias Bläsing

unread,
May 21, 2021, 1:25:39 PM5/21/21
to jna-...@googlegroups.com
Hi,

I had a quick look at the code and indeed you hit a limitation of the
structure implementation of NativeMapped.

Arrays and normal type mapped values are special cased in
validateField, but in the end NativeMapped values are also typemapped.

Greetings

Matthias

Am Montag, dem 10.05.2021 um 03:54 -0700 schrieb 'falco' via Java
Native Access:
> --
> You received this message because you are subscribed to the Google
> Groups "Java Native Access" group.
> To unsubscribe from this group and stop receiving emails from it,
> send
> an email to jna-users+...@googlegroups.com.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/jna-users/491df919-b04e-4e6c-841b-b0d0f940c75bn%40googlegroups.com
> .


Falco Dürsch

unread,
Jun 23, 2021, 9:02:50 AM6/23/21
to jna-...@googlegroups.com
Hello Matthias,

Thank you very much for looking into it. Is this a limitation / bug you would accept an PR for?

I currently work around a similar problem with `ByteBuffer`. JNA can write a NativeMapped `ByteBuffer` to native memory, but fails to read it back after the method call completed. I’d consider adding test cases and fixes for both scenarios.

Best,
Falco
> You received this message because you are subscribed to a topic in the Google Groups "Java Native Access" group.
> To unsubscribe from this topic, visit https://groups.google.com/d/topic/jna-users/lOzmj_uJEfk/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to jna-users+...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/jna-users/65a8cbc4053dd4974a8b29553494d2f9cf7138bd.camel%40doppel-helix.eu.

Matthias Bläsing

unread,
Jun 24, 2021, 3:20:07 PM6/24/21
to jna-...@googlegroups.com
Hi Falco,

Am Mittwoch, dem 23.06.2021 um 15:02 +0200 schrieb 'Falco Dürsch' via Java Native Access:
>
> Thank you very much for looking into it. Is this a limitation / bug
> you would accept an PR for?
>
> I currently work around a similar problem with `ByteBuffer`. JNA can
> write a NativeMapped `ByteBuffer` to native memory, but fails to
> read it back after the method call completed. I’d consider adding
> test cases and fixes for both scenarios.
>

yes patches are welcome. There is no guarantee for merge, but you'll
get best effort to help getting changes in line.

Greetings

Matthias

Reply all
Reply to author
Forward
0 new messages