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.
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!
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 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).
At the moment, JNI Cookbook targets Linux and macOS. It should work on both platforms without any issues.
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)
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}
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.
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.
I won't force you to do so, but you are always welcome to read this book.
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 can't make everybody happy. Make sure to double check previous points.
No, thank you.
No, thank you.
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.
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.