{"id":28376884,"url":"https://github.com/udevbe/jaccall","last_synced_at":"2026-05-28T07:02:37.897Z","repository":{"id":81597150,"uuid":"44863004","full_name":"udevbe/jaccall","owner":"udevbe","description":"Ja[va] C call[ing]","archived":false,"fork":false,"pushed_at":"2017-05-04T19:00:03.000Z","size":1192,"stargazers_count":12,"open_issues_count":1,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2026-02-12T10:48:22.105Z","etag":null,"topics":["c","ffi","function-pointer","java","jna","jni","native","pointer","pointer-api","pointer-types","wrapper"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"lgpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/udevbe.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2015-10-24T11:21:28.000Z","updated_at":"2024-03-20T13:09:58.000Z","dependencies_parsed_at":"2023-03-13T20:08:15.275Z","dependency_job_id":null,"html_url":"https://github.com/udevbe/jaccall","commit_stats":null,"previous_names":["zubnix/jaccall"],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/udevbe/jaccall","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/udevbe%2Fjaccall","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/udevbe%2Fjaccall/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/udevbe%2Fjaccall/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/udevbe%2Fjaccall/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/udevbe","download_url":"https://codeload.github.com/udevbe/jaccall/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/udevbe%2Fjaccall/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33597808,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-28T02:00:06.440Z","response_time":99,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["c","ffi","function-pointer","java","jna","jni","native","pointer","pointer-api","pointer-types","wrapper"],"created_at":"2025-05-30T00:30:30.273Z","updated_at":"2026-05-28T07:02:37.890Z","avatar_url":"https://github.com/udevbe.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"Intro\n=====\n\nJaccall makes C libraries accessible from Java without the need to write any native code. It is project similar to JNA or BridJ.\n\nStatus: \n- available on maven central: 1.0.5\n- All major features implemented. In maintenance mode.\n- Feature complete [ Linker API, Pointer API, Struct API, Function Pointer API ]\n- [![Build Status](https://travis-ci.org/udevbe/jaccall.svg?branch=master)](https://travis-ci.org/udevbe/jaccall)\n\nJaccall's does not try to be Java, but instead tries to make C accessible in Java.\n - What you allocate, you must free yourself. watch out for memory leaks!\n - Cast to and from anything to anything. Watch out for cast mismatches!\n - Read and write to and from anything to anything. Watch out for segfaults!\n\nDesign goals:\n - Simple usage.\n - Simple runtime API.\n - No config files.\n - C only.\n - Support for Linux: aarch64, armv7hf, armv7sf, armv6hf, x86_64, i686.\n - Support for all common use cases: unions, callbacks, pointer-to-pointer, ...\n \n#### Comparison with other libraries\n\nJaccall was born out of a frustration with existing solutions. Existing solutions have the nasty trade-off of having a complete but cumbersome API and slow runtime, or have excellent speed and good API but suffer from scope creep while lacking armhf support.\n\nJaccall tries to remedy this by strictly adhering to the KISS princicple.\n\n# Overview\n\n- [Linker API](#linker-api)\n  - [A linker example](#a-linker-example)\n  - [Mapping](#mapping)\n  - [By value By reference](#by-value-by-reference)\n  - [Internals](#internals)\n- [Pointer API](#pointer-api)\n  - [A pointer example](#a-pointer-example)\n  - [Stack vs Heap](#stack-vs-heap)\n  - [Memory read write](#memory-read-write)\n  - [Arrays](#arrays)\n  - [Address manipulation](#address-manipulation)\n  - [Pointer types](#pointer-types)\n- [Struct API](#struct-api)\n  - [A struct example](#a-struct-example)\n  - [Field definitions](#field-definitions)\n  - [Usage](#usage)\n- [Function Pointer API](#function-pointer-api)\n  - [A function pointer example](#a-function-pointer-example)\n\n# Linker API\n\nThe linker API forms the basis of all native method invocation. Without it, you wouldn't be able to call any native methods. \n\nTo call a C method, we must create a Java class where we define what C method we are interested in, what they look like and where they can be found. This is done by mapping Java methods to C methods, and providing additional information through annotations.\n\n#### A linker example\n\nC\n\nlibrary: `libsomething.so`\n\nheader: `some_header.h`\n```C\nstruct test {\n    char field0;\n    unsigned short field1;\n    int field2[3];\n    int *field3;\n};\n...\nstruct test do_something(struct test* tst,\n                         char field0,\n                         unsigned short field1,\n                         int* field2,\n                         int* field3);\n```\n\nJava\n`SomeHeader.java`\n```Java\n@Lib(\"something\")\npublic class SomeHeader {\n    static {\n        Linker.link(SomeHeader.class);\n    }\n    \n    @ByVal(StructTest.class)\n    public native long do_something(@Ptr(StructTest.class) long tst,\n                                    byte field0,\n                                    @Unsigned short field1,\n                                    @Ptr(int.class) long field2,\n                                    @Ptr(int.class) long field3);\n}\n```\nThis Java class exposes the C header file `some_header.h` to the Java side and informs the linker where these symbols (methods) can be resolved. This is done by providing the `@Lib(...)` annotation who's value must match the name part of `libsomething.so`. This whole flow is triggered by calling `Linker.link(...)`. \n\nDon't worry about the struct, that is handled in the [Struct API](#struct-api).\n\nIn order to pass data back and forth between Java and C, there are a few mapping rules to keep in mind.\n\n- Java method name must match C method name\n- Java method must be declared `native`\n- Java method must be declared `public`\n- Java method must only consist of a specific set of primitives for both arguments and return type.\n\n#### Mapping\n\nThe Java mapping tries to match it's C counterpart as close as possible. There are however a few non intuitive exceptions. Let's have a look on how C types map to their Java counterpart.\n\n| C | Java |\n|---|------|\n| unsigned char or char | byte |\n| unsigned char | @Unsigned byte |\n| short | short |\n| unsigned short | @Unsigned short |\n| int | int|\n| unsigned int | @Unsigned int|\n| long | long |\n| unsigned long | @Unsigned long |\n| long long | @Lng long |\n| unsigned long long | @Unsigned @Lng long |\n| float | float |\n| double | double |\n| struct foo | @ByVal(Foo.class) long |\n| union bar | @ByVal(Bar.class) long |\n| foo* | @Ptr(Foo.class) long|\n\nThe Java primitive types `boolean` and `char` do not have a corresponding C type and are not allowed.\n\nThe class argument for `@Ptr` is optional.\n\nArrays should be mapped as a pointer of the same type.\n\n#### By value By reference\n\nJava does not support the notion of passing by reference or by value. By default, all method arguments are passed by value in Java, inlcuding POJOs which are actually pointers internally. This limits the size of a single argument in Java to 64-bit. As such, Jaccall can not pass or return a C struct by value. Jaccall works around this problem by allocating heap memory and copyin/reading struct-by-value data. Jaccall must then only pass a pointer between Java and the native side. \n\nThe drawback of this approach is that all returned struct-by-value data must be freed manually!\n\n#### Internals\n\nJaccall has a compile time step to perform both fail-fast compile time checks and Java source code generation.\nTo aid the `Linker` in processing a natively mapped Java class, the `LinkerGenerator` does an initial pass over any `@Lib` annotated class to verify it's integrity and mapping rules. If this succeeds, it does a second pass and generates a `Foo_Jaccall_LinkSymbols.java` soure file for every `Foo.java` annotated with `@Lib`. This file should not be used by application code. This file contains linker data to aid the `Linker` in linking the required native Java methods to it's C counterpart.\n\nFor every mapped method, 4 parts of linker data are generated.\n- The method name (the C symbol name).\n- The number of arguments.\n- A LibFFI call interface.\n- A JNI signature.\n\nIf we reiterate our first mapping example\n\nC `some_header.h`\n```C\nstruct test {\n    char field0;\n    unsigned short field1;\n    int field2[3];\n    int *field3;\n};\n...\nstruct test do_something(struct test* tst,\n                         char field0,\n                         unsigned short field1,\n                         int* field2,\n                         int* field3);\n```\n\nJava `SomeHeader.java`\n```Java\n@ByVal(StructTest.class)\npublic native long do_something(@Ptr(StructTest.class) long tst,\n                                byte field0,\n                                short field1,\n                                @Ptr(int.class) long field2,\n                                @Ptr(int.class) long field3);\n```\n\nThe generated linker data for this mapping:\n`SomeHeader_Jaccall_LinkSymbols.java`\n```Java\n...\n@Generated(\"org.freedesktop.jaccall.compiletime.LinkerGenerator\")\npublic final class SomeHeader_Jaccall_LinkSymbols extends LinkSymbols {\n    public SomeHeader_Jaccall_LinkSymbols() {\n        super(new String[]{\"do_something\"},\n              new byte[]{5},\n              new long[]{JNI.ffi_callInterface(StructTest.FFI_TYPE,\n                                               JNI.FFI_TYPE_POINTER,\n                                               JNI.FFI_TYPE_SINT8,\n                                               JNI.FFI_TYPE_UINT16,\n                                               JNI.FFI_TYPE_POINTER,\n                                               JNI.FFI_TYPE_POINTER)},\n              new String[]{\"(JBSJJ)J\"});\n    }\n}\n```\n\n- `\"do_something\"` The name of the method\n- `5` The number of arguments\n- `JNI.ffi_callInterface(...)` The libffi call interface.\n- `\"(JBSJJ)J\"` The JNI method signature.\n\nLinker data of different methods matches on array index.\n\n# Pointer API\n\n#### A pointer example\n\nC\n```C\n...\nsize_t int_size = sizeof(int);\nvoid* void_p = malloc(int_size);\nint* int_p = (int*) void_p;\n...\nfree(int_p);\n```\nThis example is pretty self explenatory. A new block of memory is allocated of size 'int'. This block of memory is then cast to a pointer of type int, and finally the memory is cleaned up.\n\nUsing Jaccall this translates to\n```Java\n//(Optional) Define a static import of the Pointer and Size classes \n//to avoid prefixing all static method calls.\nimport static Pointer.*\nimport static Size.*\n...\n//Calculate the size of Java type `Integer` wich corresponds to a C int.\nint int_size = sizeof((Integer)null);\n//Allocate a new block of memory, using `int_size` as it's size.\nPointer\u003cVoid\u003e void_p = malloc(int_size);\n//Do a pointer cast of the void pointer `void_p` to a pointer of type `Integer`.\nPointer\u003cInteger\u003e int_p = void_p.castp(Integer.class);\n...\n//free the memory pointed to by `int_p`\nint_p.close();\n```\n\n#### Stack vs Heap\n\nC has the concept of stack and heap allocated memory. Unfortunately this doesn't translate well in Java. Jaccall tries to alleviate this by utilizing Java's garbage collector mechanism. To understand the idea behind this, it's important to know the difference between memory allocated with `Pointer.malloc(..)` and `Pointer.nref(..)`. \n\nA pointer that refers to `malloc` memory is not subject to Java's garbage collector and will never be freed manualy. Just like in C, the program is expected to free the memory when it's done with it.\n\nA pointer that refers to `nref` memory is subject to Java's garbage collector and as such requires no manual call to free. It is meant to mimic C's stack allocated memory. It is strongly advices to use this memory solely within the scope of the method that called `nref`.\n\nOne can also specifically scope heap allocated memory as Jacall defines a `Pointer\u003c...\u003e` as an `AutoClosable`. Using Java's try-with-resource concept, we can precisely scope heap allocated memory. \n\nDo not use try-with-resource on `nref` allocated memory, as it will result in a segfault caused by a double `free`.\n\nC\n```C\nint some_int = 5;\nint* int_p = \u0026some_int;\n...\n//`int_p` becomes invalid once method ends\n```\n\nUsing Jaccall `nref` this translates to\n```Java\n//(Optional) Define a static import of the Pointer class to avoid prefixing all static method calls.\nimport static Pointer.*\n...\n//define an integer\nint some_int = 5;\n//allocate a new block of scoped memory with `some_int` as it's value.\nPointer\u003cInteger\u003e int_p = nref(some_int);\n...\n//`int_p` becomes invalid once Java's garbage collector kicks in.\n```\n\nUsing Jaccall `malloc` this translates to\n```Java\n//(Optional) Define a static import of the Pointer class to avoid prefixing all static method calls.\nimport static Pointer.*\nimport static Size.*\n...\n//define an integer\nint some_int = 5;\n//allocate a new block of scoped memory with `some_int` as it's value.\ntry(Pointer\u003cInteger\u003e int_p = malloc(sizeof(some_int).castp(Integer.class)){\nint_p.write(some_int);\n ...\n}\n...\n//`int_p` becomes invalid once try block ends.\n```\n\nThere are some notable differences between the C and Java example. In the C example, only one block of memory is used to define `some_int`, `int_p` is simply a reference to this memory. This block of memory is method scoped (stack allocated). Once the method exits, the memory is cleaned up. \n\nOn the Java side however things are a bit different. A Java object (primitive) is defined as `some_int`. Next a new block of memory `int_p` is allocated on the heap, and the value of `some_int` is copied into it. This operation is reflected in the call `Pointer.write(some_int)`. Because we defined `int_p` inside a try-with-resources, it will be freed automatically with a call to `close()` once the try block ends.\n\nIt is important to notice that there is nothing special about `Pointer.nref(some_int)`. It's merely a shortcut for\n```Java\nPointer.malloc(Size.sizeof(some_int)).castp(Integer.class).write(some_int);\n```\nbut unlike a plain `malloc` has it's lifecycle tracked by the Java garbage collector.\n\n#### Memory read write\n\nLet's extend our first basic example and add some read and write operations.\n\nC\n```C\n...\nsize_t int_size = sizeof(int);\nvoid* void_p = malloc(int_size);\nint* int_p = (int*) void_p;\n*int_p = 5;\nint int_value = *int_p;\n...\nfree(int_p);\n```\n\nThe equivalent Java code:\n```Java\nimport static Pointer.*\nimport static Size.*\n...\nint int_size = sizeof((Integer)null);\nPointer\u003cVoid\u003e void_p = malloc(int_size);\nPointer\u003cInteger\u003e int_p = void_p.castp(Integer.class);\n//write an int with value 5 to memory\nint_p.write(5);\n//read (dereference the pointer) an int from memory\nint int_value = int_p.dref();\n...\nint_p.close();\n```\n\nThe data that can be written and read from a pointer object in Jaccall depends on data type it refers to. This is why it's necessary that we perform a pointer cast using `castp(Integer.class)`. This creates a new pointer object that can read and write integers.\n\nThere are 3 different cast operations that can be performed on a pointer object.\n - an ordinary cast, using `cast(Class\u003c?\u003e)`. Cast a pointer to any primitive or struct type.\n - a pointer cast, using `castp(Class\u003c?\u003e)`. Cast a pointer to a pointer of another type.\n - a pointer to pointer cast, using `castpp()`. Cast a pointer to a pointer-to-pointer.\n\nStarting from our basic example\n```Java\nimport static Pointer.*\nimport static Size.*\n...\nint int_size = sizeof((Integer)null);\nPointer\u003cVoid\u003e void_p = malloc(int_size);\n\n//Perform a pointer cast, the resulting pointer can be used to read and write an integer.\nPointer\u003cInteger\u003e int_p = void_p.castp(Integer.class);\nint_p.write(5);\nint int_value = int_p.dref();\n\n//Perform a pointer to pointer cast.\nPointer\u003cPointer\u003cInteger\u003e\u003e int_pp = int_p.castpp();\n//Dereferencing will cause a pointer object to be created with address 5, or possibly even segfault on a 64-bit system!\nPointer\u003cInteger\u003e bad_int_p = int_pp.dref();\n\n//Perform an ordinary cast, `some_long` will now contain the address of our `int_p` pointer!\nlong some_long = int_p.cast(Long.class);\n...\nint_p.close();\n```\n\nIn most cases, an ordinary cast using `cast(Class\u003c?\u003e)` will not be needed.\n\nBeware that when casting to a pointer-to-pointer using `castp(Pointer.class)`, you will end up with a `Pointer\u003cPointer\u003c?\u003e\u003e` object. You will be able to dereference the `Pointer\u003cPointer\u003c?\u003e\u003e` object to the underlying `Pointer\u003c?\u003e`, but you will not be able to write or dereference this resulting pointer as Jaccall does not know what type it should refer too. Internally Jaccall will represent the `Pointer\u003c?\u003e` object as a `Pointer\u003cVoid\u003e`.\n\nIt might not be immediatly obvious at first but using `castp(Class\u003c?\u003e)` and `castpp()` we can cast any pointer to any other type of pointer-to-pointer-to-pointer ad infinitum.\n\nAn example where we receive an address from a jni library. We know the address represents a `char***`, and as such want to create a `Pointer\u003cPointer\u003cPointer\u003cByte\u003e\u003e\u003e`.\n```Java\n//get a native address from a jni library.\nlong some_native_address = ...;\n//wrap the address in a untyped pointer\nPointer\u003cVoid\u003e void_p = Pointer.wrap(some_native_address);\n//cast to a byte pointer\nPointer\u003cByte\u003e byte_p = void_p.castp(Byte.class);\n//cast to a pointer-to-pointer\nPointer\u003cPointer\u003cByte\u003e\u003e byte_pp = byte_p.castpp();\n//cast to a pointer-to-pointer-to-pointer\nPointer\u003cPointer\u003cPointer\u003cByte\u003e\u003e\u003e byte_ppp = byte_pp.castpp();\n```\nWe can rewrite the above example more briefly\n```Java\nimport static Pointer.*\n...\nlong some_native_address = ...;\n//wrap in a pointer-to-pointer-to-char pointer\nPointer\u003cPointer\u003cPointer\u003cByte\u003e\u003e\u003e byte_ppp = wrap(Byte.class,some_native_address).castpp().castpp();\n```\n\n#### Arrays\n\nUp until now we've worked with single element pointers. Because a C array can be represented as a pointer, accessing a C array is surprisingly easy. Our pointer object knows the size of the type it's refering to, which in turn makes indexed read and writes straightforward.\n\nWe reiterate our previous read/write example, only this time we allocate space for multiple integers.\n```Java\nimport static Pointer.*;\nimport static Size.*;\n...\nint int_size = sizeof((Integer)null);\n//allocate space for 3 integers\nPointer\u003cVoid\u003e void_p = malloc(int_size*3);\n//cast to an ordinary int pointer\nPointer\u003cInteger\u003e int_p = void_p.castp(Integer.class);\n\n//write an int with value 5 to index 0.\nint_p.writei(0,5);\n//write an int with value 6 to index 1.\nint_p.writei(1,6);\n//write an int with value 7 to index 2.\nint_p.writei(2,6);\n\n//dereference the pointer at index 0\nint int_value_0 = int_p.dref(0);\n//dereference the pointer at index 1\nint int_value_1 = int_p.dref(1);\n//dereference the pointer at index 2\nint int_value_0 = int_p.dref(2);\n...\nint_p.close();\n```\n\nWe can also use `Pointer.nref(...)` to allocate an array.\n```Java\nimport static Pointer.*;\n...\n//nref uses a vararg parameter, so we can use it with both arrays and classic function arguments\nPointer\u003cInteger\u003e int_p_varargs = nref(1,2,3,4,5);\nInteger[] array = {1,2,3,4,5);\nPointer\u003cInteger\u003e int_p_array = nref(array);\n```\n\n#### Address manipulation\n\nIn C, one can read and change the actual address value of a pointer. In Jaccall this is no different. The pointer object exposes it's address either directly through an `address` field of type `long`, or it can be casted to a long.\n```Java\nPointer\u003cVoid\u003e void_pointer = ...\n//`void_pointer_adr` now contains the actual address of `void_pointer`\nlong void_pointer_adr = void_pointer.address;\n//`void_pointer_adr_cast` now contains exactly the same value as `void_pointer_adr`.\nlong void_pointer_adr_cast = void_pointer.cast(Long.class)'\n```\n\nWe can also easily offset a pointer address while keeping the type it points to.\n```Java\nPointer\u003cString\u003e char_pointer = ...\n//`char_pointer_offset` address is now incremented by 2 compared to `char_pointer` address.\nPointer\u003cString\u003e char_pointer_offset = char_pointer.offset(2);\n```\n\n#### Pointer types\n\nA pointer object only supports a limited amount of Java types it can refer to. This is because it has to perform a mapping operation from the underlying C type to the equivalent Java type.\n\nFollowing types are supported\n\n| C | Java|\n-----|-----\n| void | Void or void |\n| char | Byte or byte | \n| unsigned short or short | Short or short | \n| unsgined int or int | Integer or int |\n| unsigned long or long | CLong | \n| unsigned long long or long long | Long or long | \n| float | Float or float | \n| double | Double or double | \n| foo* | Pointer | \n| char* | String |\n\nJava primitives like boolean (Boolean) or char (Character) are not supported for the simple reason that they do not have a good C counterpart. A boolean type does not exist in C, and a Java char is actually an unsigned 16-bit integer that is used as an utf-16 character as opposed to C's 8-bit char type.\n\n# Struct API\n\n#### A struct example\n\nJaccall allows you to map any struct or union type in Java. Let's have a look at our previous example that contained a struct definition:\n\nC\n```C\nstruct test {\n    char field0;\n    unsigned short field1;\n    int field2[3];\n    int *field3;\n};\n...\n```\nMapping this struct in Java using Jaccall\n```Java\n...\nimport static CType.CHAR;\nimport static CType.INT;\nimport static CType.POINTER;\nimport static CType.UNSIGNED_SHORT;\n...\n@Struct(value = {\n    @Field(type = CHAR,\n           name = \"field0\"),\n    @Field(type = UNSIGNED_SHORT,\n           name = \"field1\") ,\n    @Field(type = INT,\n           cardinality = 3,\n           name = \"field2\"),\n    @Field(type = POINTER,\n           dataType = int.class,\n           name = \"field3\")\n})\npublic class Test extends Test_Jaccall_StructType {\n}\n```\n\nMapping a union is completely analogue.\nC `some_header.h`\n```C\nunion test {\n    char field0;\n    int field1;\n};\n...\n```\n\nIn Java this becomes\n```Java\n...\nimport static CType.CHAR;\nimport static CType.INT;\n...\n@Struct(value = {\n    union = true,\n    @Field(type = CHAR,\n           name = \"field0\"),\n    @Field(type = INT,\n           name = \"field1\"),\n})\npublic class Test extends Test_Jaccall_StructType {\n}\n```\n\nThe `@Struct` annotation defines the layout of the native C struct in Java. This layout is parsed during compilation to generate accessor code. This generated code is put in a Java class with name `Foo_Jaccall_StructType`, where `Foo` is the name of the class that has the `@Struct` annotation. To use this accessor code, simply extend the generated class. In our exmaple this becomes `extends Test_Jaccall_StructType`.\n\nThe generated accessor class is part of the internal Jaccall API and should never be used directly. Instead always inherit from it.\n\nThe following rules apply when annotating a class with `@Struct`.\n- A class annotated with `@Struct` must have a default no-arg constructor.\n- A class annotated with `@Struct` must not be abstract.\n- A class annotated with `@Struct` must have at least one `@Field`.\n- A class annotated with `@Struct` must extend the equivalent generated accessor class.\n- A class annotated with `@Struct` must have unique `@Field` names.\n- A class annotated with `@Struct` must not have a static field with name `SIZE`.\n- A class annotated with `@Struct` must be public.\n- A class annotated with `@Struct` must be a class.\n- A class annotated with `@Struct` must be a top level class.\n\n#### Field definitions\nTODO\n\n#### Usage\n\nUsing a Jaccall struct in Java is very similar as how you would use a C struct. You can create a new one directly\n\nC\n```C\nstruct test testStruct;\ntestStruct.field0 = (char)123;\n...\nint field1 = testStruct.field1;\n```\n\nJava\n```Java\nTest testStruct = new Test();\ntestStruct.field0((byte)123);\n...\nint field1 = testStruct.field1();\n```\n\nor you can allocate a block of memory first, and map it as a struct.\n\nC\n```C\nvoid* voidPointer = malloc(sizeof(struct test));\nstruct test *testPointer = (struct test *) voidPointer;\nstruct test testStruct = *testPointer;\ntestStruct.field0 = (char)123;\n...\nint field1 = testStruct.field1;\n```\n\nJava\n```Java\nPointer\u003cVoid\u003e voidPointer = Pointer.malloc(Test.SIZE);\nPointer\u003cTest\u003e testPointer = voidPointer.pcast(Test.class);\nTest testStruct = testPointer.dref();\ntestStruct.field0((byte)123);\n...\nint field1 = testStruct.field1();\n```\n\nThe important difference between the 2 cases is that the first one creates a struct on the stack (for C), which translated to memory subject to garbage collection in Java. While in the second case the memory has to be mannually freed.\n\nTo get a pointer to a 'stack' allocated struct, use `Pointer.ref(..)`. This will consistently return the same address of the struct.\n\n#### Ref vs Nref\n\nIn our previous (non struct) examples we saw that a call to `nref` would allocated a new block of managed memory and return it's address. This in contrast with `ref`, which consistenly returns the same memory address and only accepts a struct. The important difference to notice here is that `nref` is short for 'new reference', while `ref` simply means 'reference', as the 'new' already happened with a call to `new FooStruct()`.\n\nThe important thing to remember here is that in the case of `nref` the memory lifecycle is determined by the pointer object that was returned. In case of `ref` the memory lifecycle is determined by struct object itself.\n\n# Function Pointer API\n\n#### A function pointer example\n\nC\n```C\ntypedef char(*testFunc)(struct test*, unsigned int, struct test);\n```\n\nJava\n```Java\n@Functor\npublic interface TestFunc {\n    byte $(@Ptr(TestStruct.class) long arg0, @Unsigned int arg1, @ByVal(TestStruct.class) long arg2);\n}\n```\n\nDefining a single method interface as a `@Functor` will signal Jaccall to generate Java stubs as well as a factory for instantiating those stubs. The rules for mapping a function pointer are the same as for mapping a native method in the Linker API, in addition the method name MUST be defined as `$`. This allows a user to go from a C pointer to a callable Java object, as well as defining a Java method and expose it as a C function pointer!\n\nThe factory is generated in the same package as the annoated interface, and will have it's named derived from the declared interface: `Pointer+\u003cinterface name\u003e`. The factory for our `TestFunc` will thus be named `PointerTestFunc`.\n\nThe generated factory can be used like this.\n\nWhen invoking a function pointer from C:\n```Java\n//get an address from C through jni or jacall.\nlong c_func_ptr = ...;\n//wrap the address so we can invoke it on the Java side.\nPointerTestFunc cFuncPointer = PointerTestFunc.wrapFunc(c_func_ptr);\n...\n//invoke the function, this will execute the actual C function.\ncFuncPointer.$(arg0, arg1, arg2);\n...\n//PointerTestFunc extends from the Pointer class, and as such, is a pointer itself.\nassert(cFuncPointer.address == c_func_ptr);\n```\n\nWhen constructing a function pointer from Java.\n```Java\n//the implementation in Java of a C function\npublic byte javaFunction(@Ptr(StructType.class) final long arg0, @Unsigned final int arg1, @ByVal(TestStruct.class) final long arg2) {\n...\n}\n...\n//create a new function pointer that points to the above java function.\nfinal PointerTestFunc pointerTestFunc = PointerTestFunc.nref(new TestFunc() {\n                    @Override\n                    public byte $(@Ptr final long arg0, @Unsigned final int arg1, @ByVal(TestStruct.class) final long arg2) {\n                        return javaFunction(arg0, arg1, arg2);\n                    }\n                });\n\n//or more briefly (Java 8)\nfinal PointerTestFunc pointerTestFunc = PointerTestFunc.nref(this::javaFunction);\n...\n//pass on the function pointer address to the native side\nsomeNativeFunction(pointerTestFunc.address);\n...\n//we can also execute the function pointer in Java\npointerTestFunc.$(arg0, arg1, arg2);\n```\n\nIt's important to notice that a a call to `nref` in this case will not (yet) automatically reclaim memory once the functor object goes out of scope. As such it is a source of potential memory leaks which will be addressed in a future release of Jaccall.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fudevbe%2Fjaccall","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fudevbe%2Fjaccall","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fudevbe%2Fjaccall/lists"}