| name | jni-type-conversion |
| description | How to use @JniType annotations for ergonomic JNI. Relevant for Java files that use @NativeMethods or @CalledByNative. |
JNI Type Conversion
This skill guides the process of replacing explicit JNI conversion logic (like
ConvertJavaStringToUTF8) with @JniType annotations in Java and corresponding
native types in C++.
Workflow
- Read
third_party/jni_zero/README.chromium.md for a primer on JNI Zero.
- Identify Candidates: Look for JNI methods (annotated with
@NativeMethods or @CalledByNative) that take or return types that are
currently being explicitly converted in C++.
- Discovery (CRITICAL): To see if a type already has a
@JniType
conversion defined, search the codebase for FromJniType or ToJniType
definitions for that C++ type:
rg -g "*.h" "\binline .*(From|To)JniType"
If a conversion exists, note the header file where it is defined; you will
need to include it from any C++ files that require the conversion.
- Check C++ Implementation: Verify that the C++ side performs explicit
conversions using functions like:
ConvertJavaStringToUTF8 -> std::string
ConvertJavaStringToUTF16 -> std::u16string
JavaIntArrayToIntVector -> std::vector<int32_t>
ToJavaArrayOfStrings -> std::vector<std::string>
base::android::ConvertJavaStringToUTF8 -> std::string
- Verify Constraints: Do NOT convert if:
- The conversion is conditional (e.g., inside an
if block that might skip
it).
- The conversion happens inside a lambda (e.g.,
TRACE_EVENT macros). Moving
these to @JniType makes the conversion eager, which can impact
performance.
- Annotate Java:
- Add
@JniType("cpp_type") to the parameter or return type.
- For
String parameters, @JniType("std::string") automatically converts
Java null to C++ "". Prefer this over std::optional<std::string>
unless the C++ logic specifically distinguishes between null and empty.
- Binary Data: Use
@JniType("std::vector<uint8_t>") for byte[].
- Null Safety: Keep
@Nullable in Java if the parameter can be null. For
@Nullable String, using std::optional<std::string> in C++ will map
null to std::nullopt.
- Ensure
org.jni_zero.JniType is imported.
- Update C++:
- Change the C++ parameter type to the native type (e.g.,
const std::string&, std::vector<int32_t>&, base::OnceClosure).
- Remove the explicit conversion calls and intermediate variables.
- Remove Unused JNIEnv: If the
JNIEnv* env parameter used to be used,
but is no longer used after @JniType additions, it should be removed from
the C++ function signature.
- Remove Unused Callers: For non-static
@NativeMethods, the caller
parameter is usually unnecessary. Remove it from Java and C++ to reduce
boilerplate.
- Remove Unused using statements: Aliases of conversion functions might
no longer have any uses. e.g.: "using base::android::ConvertJavaStringToUTF8"
- Include Order: Specialization headers MUST be included before the
generated
_jni.h file.
- Include the header file that defines the FromJniType / ToJniType conversion
functions.
- E.g.: Include
base/android/jni_string.h for all string conversions.
- E.g.: Include
third_party/jni_zero/default_conversions.h for containers
(std::vector, std::optional, base::span).
- E.g.: Include
base/android/callback_android.h for callback conversions.
- Validate (CRITICAL): Changes are INCOMPLETE until you have verified they
build. Build all .cc and .java files to ensure JNI generation and compilation
succeed.
- Build using a command like:
autoninja -C OUTPUT_DIR ../../path/to/foo.cc^ ../../path/to/Foo.java^ ...
- Paths must be relative to
OUTPUT_DIR (e.g. start with ../../)
- The "^" suffix means "build all targets that have this input.
- Do not guess the
OUTPUT_DIR you must have been told it.
- If you cannot build, you MUST state this clearly and summarize the changes
made.
Common Recipes
base::Uuid Handling
Java: @JniType("std::string") String uuid C++:
base::Uuid::ParseLowercase(uuid_string) (incoming) or
uuid.AsLowercaseString() (outgoing).
Collection Return Types
@JniType("std::vector<...>") works for return types. C++ can return a
std::vector and it will be automatically converted to a Java array or List.
Examples
Callback Parameter
Java:
void doSomething(@JniType("base::OnceClosure") Runnable callback);
C++:
#include "base/android/callback_android.h"
void JNI_MyClass_DoSomething(base::OnceClosure callback) {
std::move(callback).Run();
}