Singapore City View: I don’t understand why writers put unrelated pictures in their articles.

Cross platform mobile development Part IV

How to pass a ByteBuffer from Java to C++ with Djinni

It’s been a while since my last article on Medium (There goes my 2018’s resolution to write an article every month). In NetVirta, I am responsible to integrate a brand new C++ library to an Android library, which itself can be consumed by an Android application be it native applications, React Native or even the spanking hot Flutter which I have so much fun playing with during my own free time.

So I was using Djinni to do all the heavy lifting for me to generate JNI codes. It took me a bit of time to get used to Djinni and I do not regret spending time learning and using it. I shuddered at the thoughts of writing and maintaining them manually. Without further ado, let’s dive straight back to the wonderful world of Djinni.

Djinni’s Data Types

Continue from my last article. We know how to pass primitives and data types that are allowed by Djinni. So the below are from the Djinni repository’s README.

The available data types for a record, argument, or return value are:

  • Boolean (bool)
  • Primitives (i8, i16, i32, i64, f32, f64).
  • Strings (string)
  • Binary (binary). This is implemented as std::vector<uint8_t> in C++, byte[] in Java, and NSData in Objective-C.
  • Date (date). This is chrono::system_clock::time_point in C++, Date in Java, and NSDate in Objective-C.
  • List (list<type>). This is vector<T> in C++, ArrayList in Java, and NSArray in Objective-C. Primitives in a list will be boxed in Java and Objective-C.
  • Set (set<type>). This is unordered_set<T> in C++, HashSet in Java, and NSSet in Objective-C. Primitives in a set will be boxed in Java and Objective-C.
  • Map (map<typeA, typeB>). This is unordered_map<K, V> in C++, HashMap in Java, and NSDictionary in Objective-C. Primitives in a map will be boxed in Java and Objective-C.
  • Enumerations / Flags
  • Optionals (optional<typeA>). This is std::experimental::optional<T> in C++11, object / boxed primitive reference in Java (which can be null), and object / NSNumber strong reference in Objective-C (which can be nil).
  • Other record types. This is generated with a by-value semantic, i.e. the copy method will deep-copy the contents.

In this article I will demonstrate how to use types that are not generated by Djinni, such as java.nio.ByteBuffer. One of the use cases is doing OpenCV projects where we want to pass the ByteBuffer from a camera Image to the C++ side.


In dealing with C++ image recognition libraries, we often need to send a ByteBuffer from the camera to the C++ side as a char pointer (char*).

There are a few steps to achieve it. To understand how this works we need to look at the generated Djinni code for the types that are supported by Djinni. Checkout the generated JNI code to pass a simple string from the Java side to C++ side.

It is found in <your_dev_folder>/djinni/support-lib/jni/Marshal.hpp

You can see on line 8 and line 14, they are toCpp() and fromCpp() methods. So what are they? You should be able to guess it already. This is where Djinni convert Java to C++ and vice versa. From the repository README, it is written that:

These files can be created by hand as long as you follow the required format. This allows you to support types not generated by Djinni.

There are three steps:

  1. Create and update a header file containing the fromCpp() and toCpp() methods. Write the conversion code there.
  2. Create and update the YAML file to allow .djinni file to utilise the custom data type.
  3. Update the .djinni file
  4. Run Djinni to generate the JNI code.

First step

Create and update a header file containing the fromCpp() and toCpp() methods. We can get the byte pointer from env->GetDirectBufferAddress() and cast it to int8_t*.

Second step

Create and update the YAML file to allow .djinni file to utilise the custom data type.

There are a few notes that I have to point out.

  • I left objc and objcpp with empty strings. Apparently it will only work if all the fields below are in place and will error out if you left them out.
  • I put the value of header under cpp as '<string>’ because it doesn’t accept null value. And an empty string will generate a #include '' linker file that prevents your code from compilation.
  • The value of header under jni must be relative to the JNI code generated by Djinni.

Third step

Update the .djinni file.

Last step

Run djinni to generate the linking code. Do checkout the first post if you haven’t yet to learn how to do it. :)

Bringing them all together

So with the generated classes, we can now pass the RGB ByteBuffer to the C++ side as a pointer.

And finally use the code at the C++ side.

I hope that this article will be able to help you if you are facing this particular problem.

My previous posts about Djinni:

  1. PART I
  2. PART II




Mobile developer; Netvirta; Android; Flutter; Gradle; Kotlin

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

The Basics: The Loop

Cluck loading screen

Day 1 of Learning C#: I think I kinda like it

One-step Install+Save for Python Dependencies

why running ps command without options on shell shows only two entries?

What does ' if __name__ == "__main__": ' do?

Count the Number of Worksheets in Excel Using Java

Tutorial Fuzzy Logic Mamdani for Arduino

Tutorial Fuzzy Logic Mamdani for Arduino

Architecture patterns in Flutter

working flutter

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
JT Liew

JT Liew

Mobile developer; Netvirta; Android; Flutter; Gradle; Kotlin

More from Medium

Blind Index Pattern — Search Strategy for Encrypted Information

A Quick walkthrough: JVM

Compiling and running Java Source code using GraalVM and Oracle Java Development Kit

How to Read Multiple Barcode and QR Code with Dynamsoft Java Barcode SDK