If you are interested in stories with happy endings, you would better of reading some other book. In this book, not only there is no happy ending, there is no happy beginning, and very few happy things in the middle.
-- Lemony Snicket, The Bad Beginning
Inside this book you can find JNI related codes that I have written over years of working with JNI. I was typically preparing small samples to test some particular concepts. Sometimes, I was preparing solutions for people who were desparatelly looking for help on stackoverflow
. There is a companion material in form of text, figures, where I describe some topics in details. JNI Cookbook page can be found here: JNI Cookbook. Please note that I had no time, yet, to prepare nice and detailed explanation for each end every contept that is tackled in this book.
Building and running
Seeing is believing. This is why I have decided to provide people with not only the description of some concepts, but with working sample code as well. The code you can find in this repository is an integral part of the book.
The easiest way to build and run codes is to clone the repository and run all tests.
> git clone https://github.com/mkowsiak/jnicookbook.git
> cd jnicookbook/recipes
> make all
> make test
> make clean
Remember that you can always run each and every sample separatelly. Simply call make
inside given recipe. Let's say you want to run recipeNo001
. All you have to do is to run
> cd jnicookbook/recipes/recipeNo001
> make
/Library/Java/JavaVirtualMachines/jdk-17.0.1.jdk/...
...
> make test
/Library/Java/JavaVirtualMachines/jdk-17.0.1.jdk/...
library: :./lib
Hello world!
Ready for Java 8 and onwards
JNI Cookbook samples were adapted to Java 17
release. You shouldn't experience any issues while working with most recent release of Java
. If you have stuck with Java 8
- for any reasons - you should be able to use samples as well.
JNI Cookbook samples were tested with:
- JDK 1.8
- JDK 9
- JDK 10
- JDK 11
- JDK 12
- JDK 13
- JDK 14
- JDK 15
- JDK 16
- JDK 17
Debugging
Debugging JNI code is not quite like sitting on cloud nine. You have to attach to JVM where JNI code is running and debug native code using external tools (e.g.: gdb
, TotalView
, lldb
). When it comes to debugging JNI code, you can find some hints inside JNI Cookbook as well. Even more, you can find a screencast that demonstates how to debug JNI code using IntelliJ IDEA and CLion. In fact, there are more to come. I plan to prepare one that will discuss lldb
, one for gdb
, and last but not least one for TotalView
(this is, however, song of the future).
Requirements
At the moment, JNI Cookbook targets Linux and macOS. It should work on both platforms without any issues.
Setting up macOS system for JNI Cookbook
Make sure to install XCode. Once installed, perform installation of Command Line Tools
.
Make sure to install OpenJDK 17 or Java SE Development Kit 17).
Once installed, make sure to set JAVA_HOME
following way
export JAVA_HOME=$(/usr/libexec/java_home -v 17)
If you are one of those brave people who like to live at the edge, you can use the most recent version of OpenJDK - JDK 19.
Once installed, make sure to set JAVA_HOME
following way
export JAVA_HOME=$(/usr/libexec/java_home -v 19)
Setting up Ubuntu system for JNI Cookbook
sudo apt install openjdk-17-jdk
sudo apt install git
sudo apt install make
sudo apt install gcc
sudo apt install g++
# Inside JNI Cookbook, all the Java stuff is based on JAVA_HOME
# variable - you need it inside the env.
export JAVA_HOME=`readlink -f $(which java) | sed 's|/bin/java||'`
# We need ./lib on LD_LIBRARY_PATH
# Rememer that inside JNI code we no longer use java.library.path
# when it comes to resolving location of the shared library.
# Inside JNI we base on system's way of locating the lib.
export LD_LIBRARY_PATH=./lib:${LD_LIBRARY_PATH}
Setting up Scala
JNI Cookbook contains Scala
based samples. These samples are using JNA
to call native code. Please make sure to install most recent version of Scala
and sbt
. This will allow you to avoid following error:
Exception in thread "main" java.io.IOError:
java.lang.RuntimeException: /packages cannot be represented as URI
At the time of writing these versions were, respectivelly: Scala 3.0.1 and sbt 1.6.0.
Nobody has time for that!
Are you crazy? Do you think I have time for all that setup?
You are right, nobody has time for that. This is why this product comes with self sufficient, ready for immediate use, Docker
file. Once you start the container, everything is there. All you have to do is to build the image and run the container.
> cd docker
> docker build -t jnicookbook .
> docker run -it jnicookbook
that's it. That's all you have to do, to get all the JNI Cookbook samples ready for testing.
It's no good reading about JNI in 2021
I won't force you to do so, but you are always welcome to read this book.
I think this book is bad
I think your book is not really that good (as some people say) and it's not interesting at all.
I totally agree. After all, this is a book related to low level coding. Have you ever read really interesting book that was describing low level coding? I really doubt it. These kind of books can be informative, they might be useful, but calling them entartaining, and really good books - that's euphemism.
Live is way too short to read dull books - like this one. This is why I have prepared a list of books you should have read instead. Each week, I will post a new book that is definitely more exciting and definitely worth way more of your time rather than this one. Stay tuned. List of books that are way more interesting.
I don't like your book
I can't make everybody happy. Make sure to double check previous points.
I think you should ...
No, thank you.
I think it would be better if ...
No, thank you.
Bibliography
This book wouldn't have existed if there were no great books on various topics it tackles.
- Java Native Interface Specification, by Oracle
- The Native Intefrace, by S. Liang
- Programming in Scala, by M. Odersky
- JNA documentation, by JNA project
- Komunikacja miedzy procesami w Unixie, by J. S. Gray (tlumaczenie: P. Kresak)
- The C Programming Language, by B.W. Kernighan, D. M. Ritchie
- C++, by B. Stroustrup
I always try to quote places I got inspiration from. Sometimes it's really hard to address each and every line of the code. If some quotations are still missing, it is unintentional. If you think I have missed some well known sources, please let me know, and I am happy to double check the source and update the Bibliography
section if necesary.
Table of contents - JNI based code
Recipe ā | Short description |
---|---|
recipeĀ āĀ 001 | running simple JNI code [source] |
recipeĀ āĀ 002 | passing int value from Java to C [source] |
recipeĀ āĀ 003 | passing double value from Java to C [source] |
recipeĀ āĀ 004 | passing long value from Java to C [source] |
recipeĀ āĀ 005 | passing short value from Java to C [source] |
recipeĀ āĀ 006 | passing char value from Java to C [source] |
recipeĀ āĀ 007 | passing byte value from Java to C [source] |
recipeĀ āĀ 008 | passing boolean value from Java to C [source] |
recipeĀ āĀ 009 | passing java.lang.String value from Java to C [source] |
recipeĀ āĀ 010 | passing java.lang.String value from C to Java [source] |
recipeĀ āĀ 011 | passing primitive types from C to Java [source] |
recipeĀ āĀ 012 | passing primitives array from Java to C [source] |
recipeĀ āĀ 013 | passing primitives array from Java to C and back (commit changes) [source] |
recipeĀ āĀ 014 | passing memory allocated in C back to Java [source] |
recipeĀ āĀ 015 | handling SIGSEGV/SIGBUS in JNI code (stop JVM from crashing) [source] |
recipeĀ āĀ 016 | handling exit calls from external library called via JNI (atexit) [source] |
recipeĀ āĀ 017 | handling exit calls from external library called via JNI (-Dexit) [source] |
recipeĀ āĀ 018 | dynamic loading of library in JNI [source] |
recipeĀ āĀ 019 | throwing exception from C code [source] |
recipeĀ āĀ 020 | accessing fields of object passed as argument [source] |
recipeĀ āĀ 021 | calling function from different source file [source] |
recipeĀ āĀ 022 | Java based daemon [source] |
recipeĀ āĀ 023 | calling code from another shared library [source] |
recipeĀ āĀ 024 | calling JNI methods from Threads and how to debug them using gdb [source] |
recipeĀ āĀ 025 | calling C++ code from C wrapper [source] |
recipeĀ āĀ 026 | passing 2D arrays from Java to C [source] |
recipeĀ āĀ 027 | Calling class methods from multiple threads [source] |
recipeĀ āĀ 028 | Calling JVM class from C (first draft for thread based computations) [source] |
recipeĀ āĀ 029 | Running Java as daemon ā main daemonās loop in Java [source] |
recipeĀ āĀ 030 | Abstract method and native implementation [source] |
recipeĀ āĀ 031 | Running simple JNI code from inside JAR file [source] |
recipeĀ āĀ 032 | Calling JVM from multiple C threads [source] |
recipeĀ āĀ 033 | Comparing execution time of "Hello world!" executed from JNI/JNA/ProcessBuilder [source] |
recipeĀ āĀ 034 | Running simple JNI code from Outer class and Inner class [source] |
recipeĀ āĀ 035 | Running simple JNI code from inside JAR file with libraries it depends on [source] |
recipeĀ āĀ 037 | Passing HashMap to C code via JNI [source] |
recipeĀ āĀ 038 | Passing HashMap to C code via JNI (using two arrays) [source] |
recipeĀ āĀ 039 | Calling (from C) Java method that returns 2D array [source] |
recipeĀ āĀ 040 | Passing ByteBuffer to C code via JNI [source] |
recipeĀ āĀ 042 | Passing Set of Strings to C code via JNI [source] |
recipeĀ āĀ 043 | Settings environment variable inside JVM via JNI [source] |
recipeĀ āĀ 044 | Getting info (inside JNI code) regarding current thread using java.lang.Thread [source] |
recipeĀ āĀ 045 | Returning vector<vector > from C++ to Java [source] |
recipeĀ āĀ 046 | Filling java.util.List (passed to JNI) with data - inside C++ [source] |
recipeĀ āĀ 047 | Filling java.util.HashMap (passed to JNI) with data - inside C++ [source] |
recipeĀ āĀ 048 | Returning map<int, int> from C++ to Java [source] |
recipeĀ āĀ 049 | Redirecting JVM's System.out to file inside C code [source] |
recipeĀ āĀ 050 | How to find location of JAR from JNI [source] |
recipeĀ āĀ 051 | Very simple, Java based, 'Hello world' code - calling it from C [source] |
recipeĀ āĀ 052 | Registering native symbols without System.load [source] |
recipeĀ āĀ 053 | Accessing elements of array - GetByteArrayElements vs. GetPrimitiveArrayCritical [source] |
recipeĀ āĀ 054 | Hello Scala! [source] |
recipeĀ āĀ 055 | Unboxing primitive types from wrapper objects - method per type [source] |
recipeĀ āĀ 056 | Unboxing primitive types from wrapper objects - one method and IsInstanceOf [source] |
recipeĀ āĀ 057 | Hello Scala! I am passing structures! [source] |
recipeĀ āĀ 058 | Passing "unsigned long" to JNI [source] |
recipeĀ āĀ 059 | Using code from static library inside JNI based code [source] |
recipeĀ āĀ 060 | How to run Java code (with Log4j) from C [source] |
recipeĀ āĀ 061 | Passing std::map<std::string, std::string> from C++ to Java [source] |
recipeĀ āĀ 063 | Accessing fields of inner class [source] |
recipeĀ āĀ 064 | Running simple JNI code - using JDK9 modules [source] |
recipeĀ āĀ 065 | Very simple, Java based, 'Hello world' code - calling it from Objective-C (macOS only) [source] |
recipeĀ āĀ 066 | Embedding JVM inside macOS application bundle and calling JVM from Objective-C (macOS only) [source] |
recipeĀ āĀ 067 | Iterating over objects inside java.util.List - using get method [source] |
recipeĀ āĀ 068 | Iterating over objects inside java.util.List - using java.util.Iterator [source] |
recipeĀ āĀ 069 | Iterating over objects inside array of Objects (SimpleBean[]) [source] |
recipeĀ āĀ 070 | Passing structure by reference using JNA [source] |
recipeĀ āĀ 071 | Be carefull with errno. It can bite. [source] |
recipeĀ āĀ 072 | Handling errno using custom exception type [source] |
recipeĀ āĀ 073 | Passing errno and errno string inside wrapper class [source] |
recipeĀ āĀ 074 | Passing errno via JNI routine's arguments [source] |
recipeĀ āĀ 075 | Returning object with number of fields from JNI (constructor) [source] |
recipeĀ āĀ 076 | Returning object with number of fields from JNI (setters) [source] |
recipeĀ āĀ 077 | Passing null as method argument inside JNI [source] |
recipeĀ āĀ 078 | Surprize, surprize ! My stack is so small. [source] |
recipeĀ āĀ 079 | Passing String value from C via object passed as an argument[source] |
recipeĀ āĀ 080 | Parsing string with date inside JNI [source] |
recipeĀ āĀ D001 | debugging JNI code with CLion [source] |
recipeĀ āĀ D003 | Profiling JNI based code using Instruments.app (macOS only) [source] |
Copyright Ā© 2015-2022 Michal K. Owsiak. All rights reserved.