jnipp is a C++11 Java Native Interface wrapper supposed to make life easier.
- you need c++11 support:
-std=c++11
- compile with
-DJNIPP_USE_TYPE_TRAITS
to use type traits if available; some versions of libstdc++ do not supporttype_traits
: compile with-DJNIPP_USE_BOOST
and put boost in your include path. - some platforms (Android for example) do not completely support thread local storage. use
-DJNIPP_THREAD_LOCAL_PTHREAD
to fallback to pthread.
cd test
make -f Makefile.osx
make -f Makefile.linux
It does not work?
- recompile the generate script: cd generate; javac generate.java
- install clang
- fix include path in Makefile
#include <jnipp.h>
using namespace jnipp;
JNIEnv* jni_env_pointer = /* ... */;
Env::Scope scope(jni_env_pointer);
LocalRef<String> str = String::create("Some String!");
Method<String> String_toUpperCase("java/lang/String", "toUpperCase", "()Ljava/lang/String;");
LocalRef<String> str_upper = String_toUpperCase(str);
compile with:
clang -std=c++11 -lc++ -fvisibility=hidden -fvisibility-inlines-hidden -Wl,-dead_strip test.cpp -o test
use ./generate/generate java.lang.String
to generate the java class header file
#include <jnipp.h>
#include "_java.h" // contains the JavaLangString definition
using namespace jnipp;
JNIEnv* jni_env_pointer = /* ... */;
Env::Scope scope(jni_env_pointer);
LocalRef<JavaLangString> str = String::create("Some String!");
LocalRef<JavaLangString> str_upper = str->toUpperCase();
Please note that due to the fact that some names are reserved in C++ and C++ also does not allow fields and methods with the same name, some method or member names are made unique by appending underscores (i.e. someField_ instead of someField)
This library is designed to generate as close to manually written code as possible.
- All functions are inlined
- No additional reference counters
- No allocations
- the "test" sample produces a .dylib of 30kb
When using java class headers you need to use dead code stripping, for clang:
clang source.cpp -fvisibility=hidden -fvisibility-inlines-hidden
clang source.o -Wl,-dead_strip
- clean up generate tool (own dir, .jar, output file name option etc.)
- option to limit scope of generate tool.
-
stores the current
JNIEnv*
as a thread local variable -
use
Env::get()
to get the currentJNIEnv*
-
use
Env::peek()
to get the currentJNIEnv*
without throwing an exception if it is null -
use
Env::Scope myScope(my_jni_env)
to set theJNIEnv*
. The scope setter will restore the previous value on destruction. -
use
Env::Scope myScope(my_jni_vm)
to attach the current thread to the VM. -
use
Env::hasException()
to check if an exception has occured, Env::getException() to get the exception object. -
use
Env::throwException(exceptionObject)
orEnv::throwException(exceptionClass, stringArgument)
to throw an exception.
Ref
is an unmanaged reference (jobject
). Use these for method arguments.Ref
s are not larger than ajobject
and do not need to be passed by reference.- all
Ref
s supportoperator ==
(IsSameObject
) andoperator bool
checking (for not null) - a
LocalRef
keeps a jni local reference and callDeleteLocalRef
on destruction. Use these for returning objects. The copy constructor will callNewLocalRef
. - use
LocalRef.steal()
to get the jobject from a LocalRef and zeroing the LocalRef (i.e. preventing the call to DeleteLocalRef on destruction). - use
LocalRef::use(jobject)
to use an existing local reference jobject. - a
GlobalRef
is a java global reference (NewGlobalRef
). on destruction, callsDeleteGlobalRef
. - a
WeakRef
is a java weak global reference (NewWeakGlobalRef
). on destruction, callsDeleteWeakGlobalRef
. These are not a subclass ofRef
and can only be used to initialize aLocalRef
(to make sure that the weak reference is not garbage collected during usage).
- for arguments of type
Ref<String>
you can directly pass aconst char*
instead of passingString::create(...)
- for a
Ref<Array>
you can directly use the array subscript operator, i.e.myArrayRef[0]
instead of(*myArrayRef)[0]
Ref<String>
can be cast toconst char*
andstd::string
Ref<String>
has aoperator ==(const char*)
(and !=)
Method<returnType, argType1, argType2, argType3> method(const char* / Ref<Class> class, const char* methodName, const char* signature);
defines a method.- Same for
StaticMethod
andNonvirtualMethod
- use
method.call([thisref, ]arg1, arg2, arg3);
to call Field<type> field(const char* / Ref<Class> class, const char* fieldName, const char* signature);
defines a field- Same for
StaticField
- use
field.get([thisref])
andfield.set([thisref, ]value)
- there is also a cast and assignment operator
Constructor<classType, argType1, ...> constructor(const char* / Ref<Class> class, const char* signature);
defines a constructor.- use
constructor.construct(arg1, arg2, ..)
to call
Array<Object>
is an object array. You can uselength()
,get(index)
andset(index, newValue)
. An[]
operator exist, but only for reading.Array<Object>::construct(size, elementClass)
creates a new array.- object arrays support iterators, so you can use
for (auto something in myObjectArray)
Array<jbyte>
(or any other primitive) is a primitive array. It also supportslength()
,get(index)
andset(index, newValue)
, but works by locking the buffer into memory on first usage (GetByteArrayElements
). The subscript operators work for getting and setting, and the primitive array can also be cast to a pointer.- upon next usage as a
jobject
the buffer is unlocked (ReleaseByteArrayElements
) automatically. - you can use
lock()
andunlock()
to do this manually.
- The
generate
tool will create a header file containing all method and field definitions. - Referenced classes are included.
- Pass all java classes you need to access as parameters (i.e.
./generate java.lang.String java.util.Map java.util.Set
) - Output filename is always
_java.h
- The generated classes are named
JavaLangString
forjava.lang.String
and so on. - dont forget to turn on dead code stripping (see above), otherwise that will make your executable really large.