-
Notifications
You must be signed in to change notification settings - Fork 6
Annotations
You control JniGen output via two annotations: @ExposedToNative
, which tells it which classes to process and @CalledByNative
, which controls which class members to expose.
This annotation should be placed on the classes that you need to make accessible from native code.
When this annotation is placed on the class (let's call it SomeClass
) the following things will happen:
-
A Java type (by default named
jSomeClass
) will be declared viaDEFINE_JAVA_TYPE()
- If the class is derived from any other
@ExposedToNative
class the conversions will also be declared viaDEFINE_JAVA_CONVERSION()
- If the class is used in an array
SomeClass[]
in any exposed method or field the array type (by default namedjSomeClassArray
) will be declared viaDEFINE_ARRAY_JAVA_TYPE()
To put it simply, the annotation processor will do the 'right thing'. All the necessary object types will be declared for you without you having to worry about it. All these declarations for all types will be put in a single header (by default named
type_map.h
). You can customize the header name via annotation processor options. - If the class is derived from any other
-
If the class has any
native
methods or any members annotated with@CalledByNative
then the process will also generate a class type derived fromjava_runtime::simple_java_class
.- The native methods will be declared as static methods of this class for you to implement. Thus, if you forget to implement them or their signature changes on Java side you will get a compile/link time error.
- The members annotated with
@CalledByNative
will produce member functions with appropriate signatures as described below.
Again, the annotation processor will do the 'right thing' generating all the boilerplate code for you. The class declaration will be put into a separate header file (named
SomeClass_class.h
by default).Important note For any element annotated with
@CalledByNative
all the types in its declaration (return type and argument types) must be either standard Java types (primitive types, Object or String) or themselves annotated with@ExposeToNative
. Otherwise you will get an error during processing. What should you do if you have a type from external library you cannot annotate? See Processor Options page for info about how to handle this situation. -
Finally for all the headers for class types generated above will be included from a file named
all_classes.h
This header will also define a macroJNIGEN_ALL_GENERATED_CLASSES
which is a comma separated list of all the generated class names. This macro can be used as template parameters tojava_class_table
if you use it.
@ExposedToNative
annotation has arguments that allow customization of the names of types it generates
The default value is used to define a 'stem' for all the generated names. For example if you have
@ExposedToNative("Foo")
class SomeClass {
...
}
then the instance type will become jFoo
, the class type Foo_class
and the class type will be put in the header named Foo_class.h
. The default stem is simply the Java class name for top level classes and Outer_Inner
for inner classes.
The typeName
parameter can be used to specifically override type name ignoring the stem. For example if you have
@ExposedToNative(typename="jFoo")
class SomeClass {
...
}
then the instance type will become jFoo
and the class type SomeClass_class
in the header SomeClass_class.h
Similarly the className
parameter allows to only override the class name.
@ExposedToNative(className="Foo")
class SomeClass {
...
}
will produce jSomeClass
and Foo
in the header SomeClass_class.h
Finally header
parameter allows you to override the name of the header file generated for the class type.
@ExposedToNative(className="Foo.h")
class SomeClass {
...
}
will produce jSomeClass
and SomeClass_class
in the header Foo.h
You can put this annotation on constructors, methods (static and instance) and fields (static and instance) of a class annotated with @ExposeToNative
. When you do so the annotated element will become a method on the class type with an appropriate signature.
- For constructors the method name will
ctor
(this can be changed via processor options). - For methods the name will be the name of the Java method.
- For fields the name will be
get_<field name>
to get the value and (if the field is not final)set_<field name>
to set it.
All the boilerplate code: declaring java_method
s etc. will be hidden inside the class declaration.
If you ever need to call an instance @CalledByNative
method non-virtually you can set allowNonVirtualCall
annotation parameter to true
. This will produce an additional templated overload of the method on the C++ side that takes an extra parameter: java_class<T> &
that will invoke non-virtual call.
If you use ProGuard or built-in Android code minifier they will usually strip Java methods called only from C++ as unused. After all these tools cannot 'see inside' C++ code. Your code, then, will mysteriously fail at runtime because classes and methods C++ expects to find are not there.
The @ExposeToNative
and @CalledByNative
annotations provide an easy way to avoid this. Just tell the ProGuard to keep entities annotated with them. Something like
-keepclasseswithmembers class * {
@smjni.jnigen.CalledByNative <methods>;
}
-keepclasseswithmembers class * {
@smjni.jnigen.CalledByNative <fields>;
}
-keepclasseswithmembers class * {
native <methods>;
}
Similarly IDEs tend to add "this is unused" warnings on things that are only called from native code. You can usually configure these warnings to ignore elements with certain annotations and it is easy to add JniGen annotations to the list. For IntelliJ based IDE the relevant setting is under Inspections/Java/Declaration Redundancy/Unused declaration. Under Options click on 'Entry Points', then 'Annotations' and add JniGen annotations to the list.
- Building
-
User's Guide
Declaring Java Types
Accessing Methods and Fields
Representing Java Classes
Implementing Native Methods
Smart References
Error Handling
Obtaining JNIEnv
Initialization
Strings
Arrays
Direct Buffers
Booleans
Sizes -
JniGen Code Generator
Integrating JniGen
Annotations
Processor Options