JPassport works like Java Native Access (JNA) but uses the Foreign Linker API instead of JNI. Similar to JNA, you declare a Java interface that is bound to the external C library using method names.

Overview

JPassport

JPassport works like Java Native Access (JNA) but uses the Foreign Linker API instead of JNI. Similar to JNA, you declare a Java interface that is bound to the external C library using method names.
The goal of this project is to a) start working with the Foreign Linker, b) provide a drop in replacement for JNA in simple applications.

As part of the Foreign Linker API a tool called JExtract is available. Given a header file JExtract will build the classes needed to access a C library. If you have a large header file then JExtract is likely an easier tool for you to use if you don't already have interfaces defined for JNA.

At least Java Panama EA-17 is required to use this library.

The Foreign Linker API is still an incubator, so you can think of this project as a proof of concept at this time.

Getting Started

Download the source and run the maven build.

Example

C:

int string_length(const char* string)
{
    return strlen(string);
}

double sumArrD(const double *arr, const int count)
{
    double r = 0;
    for (int n = 0; n < count; ++n)
        r += arr[n];
    return r;
}

Java Interface:

public interface Linked extends Passport {
   int string_length(String s);
   double sumArrD(double[] arr, int count);
}

Java Usage for dynamic class creation:

Linked L = PassportFactory.link("libforeign", Linked.class);
int n = L.string_length("hello");
double sum = L.sumArrD(new double[] {1, 2, 3}, 3);

Java Usage to create a .java file for inclusion in your codebase:

PassportWriter pw = new PassportWriter(Linked.class);
pw.writeModule(Path.of('output_location'));

Once the class is compiled, to use it:

Linked l = new Linked_Impl(PassportFactory.loadMethodHandles("libforeign", Linked.class));

In order to use this library you will need to provide the VM these arguments:

-Djava.library.path=[path to lib] --enable-native-access jpassport

JPassport works by writing a class that implements your interface, compiling it and passing it back to you. By default, the classes are written to the folder specified by System.getProperty("java.io.tmpdir"). If you provide the system property "jpassport.build.home" then the classes will be written and compiled there.

Performance

Performance was tested vs JNA, JNA Direct, and pure Java.

Performance of a method that passes 2 doubles:

primative performance

Performance of a method that passes an array of doubles

array performance

(Tests were run on Windows 10 with an i7-10850H.)

C Data Types Handled Automatically

C Data Type Java Data Type
double double
double*, double[] double[]
double** @PtrPtrArg double[][]
double[][] double[][]
float float
float*, float[] float[]
float** @PtrPtrArg float[][]
float[][] float[][]
long long
long*, long[] long[]
long** @PtrPtrArg long[][]
long[][] long[][]
int int
int*, int[] int[]
int** @PtrPtrArg int[][]
int[][] int[][]
short short
short*, short[] short[]
short** @PtrPtrArg short[][]
short[][] short[][]
char byte
char* byte[] or String
char[] byte[] or String
char** @PtrPtrArg byte[][]
char[][] byte[][]
structs Records

Any C argument that is defined with ** must be annotated with @PTrPtrArg in your Java interface.

Return types can be:

  1. double
  2. float
  3. long
  4. int
  5. short
  6. char
  7. void
  8. char* (maps to a Java String)
  9. any pointer (see limitations)

If an argument is changed by the C library call then the @RefArg annotation is required for that argument. The argument also needs to be passed as an array of length one. Ex.

C:

void readB(int *val, int set)
{
    *val = set;
}

Java:

public interface Test extends Passport {
  void readD(@RefArg int[] d, int set);
}

Linked lib = PassportFactory.link("foreign_link", Test.class);
int[] ref = new int[1];
lib.readD(ref, 10);

Without the @RefArg, when ref[] is returned it will not have been updated.

Structs and Records

In order to handle C Structs you must make an equivalent Java Record. For example

struct PassingData
{
    int s_int;
    long long s_long;
    float s_float;
    double s_double;
};

struct ComplexPassing
{
    int s_ID;
    struct PassingData s_passingData;
    struct PassingData* s_ptrPassingData;
    char* s_string;
};

double passSimple(struct PassingData* complex)
{
...
}

double passComplex(struct ComplexPassing* complex)
{
...
}
import jpassport.annotations.RefArg;

public record PassingData(
        @StructPadding(bytes = 4) int s_int,
        long s_long,
        @StructPadding(bytes = 4) float s_float,
        double s_double) {
}

public record ComplexPassing(
        @StructPadding(bytes = 4) int ID,
        PassingData ts,
        @Ptr TestStruct tsPtr,
        String string) {
}

public interface PerfTest extends Passport {
    double passStruct(PassingData structData);
    double passComplex(@RefArg ComplexPassing[] complexStruct);
}

The most important thing to note here is the @StructPadding annotation. When a C compiler compiles a struct it will insert bytes of padding. It is critical for you to tell JPassport how much padding is either before or after a structure member (negative numbers indicate pre-member padding). There is no standard about what padding will be used in any situation so JPassport can't figure this out on its own (at least not that I'm aware of!). There are separate annotation values for different platforms (windowsBytes, macBytes, linuxBytes).

The other important annotation is @Ptr, this lets JPassport know to treat the member of the struct as a pointer to another struct.

Arrays of Records can only be 1 element long. Longer arrays of Records are not supported.

Records can contain primitives, arrays of primitives, pointers to arrays of primitives, Strings, or pointers to other Records.

Limitations

  • Only arrays of Records of length 1 work.
  • Only 1D and 2D arrays of primitives are supported, deeper nestings do not work.
  • The interface file passed to PassportFactory and all required Records must be exported by your module.

Pointers as function returns only work in a limited fashion. Based on a C function declaration there isn't a way to tell exactly what a method is returning. For example, returning int* could return any number of ints. There is little a library like JPassport can do to handle returned pointers automatically. The work-around is for your interface function to return MemoryAddress. From there it would be up to you to decipher the return.

Declaring your interface method to take MemoryAddress objects allow you to manage all of the data yourself (like JExtract).

double* mallocDoubles(const int count)
{
    double* ret = malloc(count * sizeof(double ));

    for (int n = 0; n < count; ++n)
        ret[n] = (double)n;

    return ret;
}

void freeMemory(void *memory)
{
    free(memory);
}
public interface TestLink extends Passport {
    MemoryAddress mallocDoubles(int count);
    void freeMemory(MemoryAddress addr);
}

double[] testReturnPointer(int count) {
    MemoryAddress address = linked_lib.mallocDoubles(count);
    double[] values = Utils.toArrDouble(address, count);
    linked_lib.freeMemory(address);
    return values;
}

Dependencies

JPassport itself only requires at least Java Panama EA-17 to build and run.

The testing classes require:

  • JNA 5.8.0
  • JUnit 5.4.2 (later versions of JUnit do not play nice with modules yet)
  • Apache Commons CSV 1.8 (only used to output performance data)

Work To-Do

Roughly in order of importance

  1. Support arrays of Records
  2. Support returning a Record
  3. Use the Java Micro-benchmarking harness.
  4. Compile classes in memory instead of from disk
You might also like...

A JavaCard applet for setting the global PIN (0x11) on a card using GlobalPlatform API

A JavaCard applet for setting the global PIN (0x11) on a card using GlobalPlatform API

Mar 4, 2022

Scaffolding is a library for Minestom that allows you to load and place schematics.

This library is very early in development and has too many bugs to count. For your own safety, you should not use it in a production environment.

Nov 29, 2022

KakaoSDK Bridge for React, React-Native, RNW

KakaoSDK Bridge for React, React-Native, RNW

KakaoSDK for React, React-Native Use Dependencies iOS Android Web 2.5.0 2.5.0 1.39.14 처음 설치 시 주의 사항 (React-Native 만) 해당 모듈은 Swift로 되어있어서 그냥 가동 시 작동이 안

May 2, 2022

React Native Typescript Boilerplate

React Native TypeScript Boilerplate Included Packages react-native-rename react-native-dotenv Instructions Basic instructions To start the development

Nov 27, 2021

A Step-by-step Guide to a Consistent Multi-Platform Font Typeface Experience in React Native

 A Step-by-step Guide to a Consistent Multi-Platform Font Typeface Experience in React Native

A Step-by-step Guide to a Consistent Multi-Platform Font Typeface Experience in React Native Goal Be able to use font typeface modifiers such as fontW

Dec 23, 2022

A Local implementation of a java library functions to create a serverside and clientside application which will communicate over TCP using given port and ip address.

A Local implementation of a java library functions to create a serverside and clientside application which will communicate over TCP using given port and ip address.

A Local implementation of java library functions to create a serverside and clientside application which will communicate over TCP using given port and ip address.

Feb 12, 2022

a little project that will help you get in jail

Heftgen [ˈhɛftçən] ausgesprochen: Heftchen Development Install this npm module globally (https://www.npmjs.com/package/git-conventional-commits) Enabl

Jun 26, 2021

Function allowing you to find duplicate in an array in linear time and constant space

Floyd's tortoise and hare Function allowing you to find duplicate in an array in linear time and constant space ! Floyd's method is a pretty amazing,

Mar 29, 2022

An app that weighs the pros and cons of a decision to help you make the best decision

An app that weighs the pros and cons of a decision to help you make the best decision

An app that weighs the pros and cons of a decision to help you make the best decision

Feb 2, 2022
Comments
  • Structure testing crashes the VM

    Structure testing crashes the VM

    The TestUsingStructs JUnit test I just made will crash the VM. If I turn off code compiling and just use a class loader to load the last class I compiled then there is no crash. I'm attaching a VM crash log.

    hs_err_pid11184.log

    opened by boulder-on 7
  • Correct the library name instruction

    Correct the library name instruction

    The library name on Linux and Mac does not include the "lib" prefix. For example, "libpng.so" is loaded with name "png".

    opened by merykitty 0
  • Write completely self contained source

    Write completely self contained source

    It would be nice if the source code that's written could be 100% self contained as an option. That would mean moving everything from Utils into the written code and all of the method lookups. I think that would leave the constructor requiring a path to any library.

    opened by boulder-on 0
  • Update JUnit 5 version

    Update JUnit 5 version

    The README says:

    JUnit 5.4.2 (later versions of JUnit do not play nice with modules yet)

    What are the issues here?

    IIRC, we introduced module descriptors around JUnit 5.5 ... 🤔

    opened by sormuras 6
Releases(v0.3.0-alpha)
Owner
null
Simple way of causing a bsod using the native api implemented into a 1.12.2 Forge mod

Simple-BSOD-Mod Simple way of causing a bsod using the native api implemented into a 1.12.2 Forge mod. Dowload It HERE To make your own you can go to

INZO_Technologies 5 Dec 28, 2022
An open source, modular alternative of sketchware. Create your own app in android using block programming like scratch!

OpenBlocks An open source, modular alternative of sketchware. Create your own app in android using block programming like scratch! What is OpenBlocks?

OpenBlocks 30 Dec 16, 2022
Live Access Serever 9 (repository: las9)

Live Access Serever 9 (repository: las9) This version of LAS has the following technical features. All configuration and management done using an Admi

Pacific Marine Environmental Laboratory 1 Mar 14, 2022
Automatically discover and tag PII data across BigQuery tables and apply column-level access controls based on confidentiality level.

Automatically discover and tag PII data across BigQuery tables and apply column-level access controls based on confidentiality level.

Google Cloud Platform 18 Dec 29, 2022
Detect uses of legacy Java APIs

Modernizer Maven Plugin Modernizer Maven Plugin detects uses of legacy APIs which modern Java versions supersede. These modern APIs are often more per

Andrew Gaul 325 Dec 12, 2022
An example mod that uses Vigilance and Essential with Java

Vigilance Example Mod (Java) I haven't really seen any mods that use Vigilance and Essential with Java, so here's a quick example mod I made. It's bas

null 6 Dec 25, 2022
Ultra-fast SQL-like queries on Java collections

CQEngine - Collection Query Engine CQEngine – Collection Query Engine – is a high-performance Java collection which can be searched with SQL-like quer

Niall Gallagher 1.6k Dec 30, 2022
Trino connectors for managing cloud resources, like AWS EC2 instances or S3 buckets.

Trino connectors for managing cloud resources, like AWS EC2 instances or S3 buckets. Please keep in mind that this is not production ready and it was created for tests.

Jan Waś 11 Nov 4, 2022
FundurASM - A Assembly-like language interpreter

FundurASM - A Assembly-like language interpreter This interpreter was written by LordBurtz Licensed under GPLv2, all rights reserved Running it Downlo

null 2 Jan 31, 2022
The project was created using the API of the Spotify application.

Spotify API The project was created using the API of the Spotify application.

Atakan Koçyiğit 3 Jan 27, 2022