0

JNI Zero: Require @JniType conversions functions to appear in .h files

This has the following advantages:
 * Missing conversions will be a compile-time error rather than
   link-time.
 * Allows us to define a default implementations that maps a pointer
   type to its dereferenced type.
 * Allows us to define a default implementations for std::optional<T>.

Bug: 334905258
Change-Id: I092261e163c88c4e3a235e7f74059c5630cb5ea2
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5559723
Code-Coverage: findit-for-me@appspot.gserviceaccount.com <findit-for-me@appspot.gserviceaccount.com>
Commit-Queue: Andrew Grieve <agrieve@chromium.org>
Reviewed-by: Mohamed Heikal <mheikal@chromium.org>
Owners-Override: Andrew Grieve <agrieve@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1305161}
This commit is contained in:
Andrew Grieve
2024-05-23 16:59:36 +00:00
committed by Chromium LUCI CQ
parent a508a345eb
commit f46caa514f
61 changed files with 669 additions and 729 deletions
base
chrome/browser
components
content/browser
third_party/jni_zero
ui/gfx/android
url/android

@ -1347,7 +1347,6 @@ component("base") {
"android/jni_array.h",
"android/jni_bytebuffer.cc",
"android/jni_bytebuffer.h",
"android/jni_conversions.cc",
"android/jni_registrar.cc",
"android/jni_registrar.h",
"android/jni_string.cc",

@ -2,19 +2,18 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/android/jni_array.h"
#include "base/android/jni_string.h"
#include "base/command_line.h"
#include "base/android/jni_string.h"
#include "build/robolectric_buildflags.h"
// Must come after all headers that specialize FromJniType() / ToJniType().
#if BUILDFLAG(IS_ROBOLECTRIC)
#include "base/base_robolectric_jni/CommandLine_jni.h" // nogncheck
#else
#include "base/command_line_jni/CommandLine_jni.h"
#endif
using base::android::ConvertUTF8ToJavaString;
using base::android::ConvertJavaStringToUTF8;
using base::android::JavaParamRef;
using base::android::ScopedJavaLocalRef;
using base::CommandLine;

@ -4,17 +4,19 @@
#include "base/android/feature_map.h"
#include <jni.h>
#include <stddef.h>
#include <memory>
#include <string>
#include <string_view>
#include "base/base_jni/FeatureMap_jni.h"
#include "base/android/jni_string.h"
#include "base/metrics/field_trial_params.h"
#include "base/notreached.h"
// Must come after all headers that specialize FromJniType() / ToJniType().
#include "base/base_jni/FeatureMap_jni.h"
namespace base::android {
std::pair<std::string_view, const Feature*> MakeNameToFeaturePair(

@ -2,10 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/base_jni/Features_jni.h"
#include "base/android/jni_string.h"
#include "base/feature_list.h"
#include "base/metrics/field_trial_params.h"
// Must come after all headers that specialize FromJniType() / ToJniType().
#include "base/base_jni/Features_jni.h"
namespace base {
namespace android {

@ -2,17 +2,18 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <jni.h>
#include <map>
#include <string>
#include "base/base_jni/FieldTrialList_jni.h"
#include "base/android/jni_string.h"
#include "base/lazy_instance.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/field_trial_list_including_low_anonymity.h"
#include "base/metrics/field_trial_params.h"
// Must come after all headers that specialize FromJniType() / ToJniType().
#include "base/base_jni/FieldTrialList_jni.h"
namespace {
// Log trials and their groups on activation, for debugging purposes.

@ -2,14 +2,16 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/files/important_file_writer.h"
#include <string>
#include "base/android/jni_array.h"
#include "base/android/jni_string.h"
#include "base/base_jni/ImportantFileWriterAndroid_jni.h"
#include "base/files/important_file_writer.h"
#include "base/threading/thread_restrictions.h"
// Must come after all headers that specialize FromJniType() / ToJniType().
#include "base/base_jni/ImportantFileWriterAndroid_jni.h"
namespace base {
namespace android {

@ -223,7 +223,7 @@ public class FileUtils {
@NativeMethods
public interface Natives {
/** Returns the canonicalised absolute pathname for |filePath|. */
@JniType("base::FilePath")
String getAbsoluteFilePath(@JniType("base::FilePath") String filePath);
@JniType("std::string")
String getAbsoluteFilePath(@JniType("std::string") String filePath);
}
}

@ -6,7 +6,6 @@
#include "base/android/jni_android.h"
#include "base/android/jni_string.h"
#include "base/android/scoped_java_ref.h"
#include "base/debug/dump_without_crashing.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
@ -14,14 +13,15 @@
#include "base/logging.h"
#include "build/robolectric_buildflags.h"
// Must come after all headers that specialize FromJniType() / ToJniType().
#if BUILDFLAG(IS_ROBOLECTRIC)
#include "base/base_robolectric_jni/JavaExceptionReporter_jni.h" // nogncheck
#else
#include "base/base_jni/JavaExceptionReporter_jni.h"
#endif
using base::android::JavaParamRef;
using base::android::JavaRef;
using jni_zero::JavaParamRef;
using jni_zero::JavaRef;
namespace base {
namespace android {
@ -39,7 +39,7 @@ LazyInstance<JavaExceptionFilter>::Leaky g_java_exception_filter =
} // namespace
void InitJavaExceptionReporter() {
JNIEnv* env = base::android::AttachCurrentThread();
JNIEnv* env = jni_zero::AttachCurrentThread();
// Since JavaExceptionReporter#installHandler will chain through to the
// default handler, the default handler should cause a crash as if it's a
// normal java exception. Prefer to crash the browser process in java rather
@ -52,7 +52,7 @@ void InitJavaExceptionReporter() {
}
void InitJavaExceptionReporterForChildProcess() {
JNIEnv* env = base::android::AttachCurrentThread();
JNIEnv* env = jni_zero::AttachCurrentThread();
constexpr bool crash_after_report = true;
SetJavaExceptionFilter(
base::BindRepeating([](const JavaRef<jthrowable>&) { return true; }));

@ -4,11 +4,8 @@
#include "base/android/java_handler_thread.h"
#include <jni.h>
#include "base/android/jni_android.h"
#include "base/android/jni_string.h"
#include "base/base_jni/JavaHandlerThread_jni.h"
#include "base/functional/bind.h"
#include "base/message_loop/message_pump.h"
#include "base/message_loop/message_pump_type.h"
@ -19,6 +16,9 @@
#include "base/threading/thread_id_name_manager.h"
#include "base/threading/thread_restrictions.h"
// Must come after all headers that specialize FromJniType() / ToJniType().
#include "base/base_jni/JavaHandlerThread_jni.h"
using base::android::AttachCurrentThread;
namespace base {

@ -1,97 +0,0 @@
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <jni.h>
#include <optional>
#include <string>
#include "base/android/jni_string.h"
#include "base/base_export.h"
#include "base/files/file_path.h"
#include "third_party/jni_zero/jni_zero.h"
namespace jni_zero {
template <>
BASE_EXPORT std::string FromJniType<std::string>(
JNIEnv* env,
const JavaRef<jobject>& input) {
return base::android::ConvertJavaStringToUTF8(
env, static_cast<jstring>(input.obj()));
}
template <>
BASE_EXPORT ScopedJavaLocalRef<jobject> ToJniType<std::string>(
JNIEnv* env,
const std::string& input) {
return base::android::ConvertUTF8ToJavaString(env, input);
}
// Enables vector<const std::string*> to avoid copies.
template <>
BASE_EXPORT ScopedJavaLocalRef<jobject> ToJniType<const std::string*>(
JNIEnv* env,
const std::string* const& input) {
if (!input) {
return nullptr;
}
return base::android::ConvertUTF8ToJavaString(env, *input);
}
template <>
BASE_EXPORT ScopedJavaLocalRef<jobject> ToJniType<const char*>(
JNIEnv* env,
const char* const& input) {
return base::android::ConvertUTF8ToJavaString(env, input);
}
template <>
BASE_EXPORT std::u16string FromJniType<std::u16string>(
JNIEnv* env,
const JavaRef<jobject>& input) {
return base::android::ConvertJavaStringToUTF16(
env, static_cast<jstring>(input.obj()));
}
template <>
BASE_EXPORT ScopedJavaLocalRef<jobject> ToJniType<std::u16string>(
JNIEnv* env,
const std::u16string& input) {
return base::android::ConvertUTF16ToJavaString(env, input);
}
// Enables vector<const std::u16string*> to avoid copies.
template <>
BASE_EXPORT ScopedJavaLocalRef<jobject> ToJniType<const std::u16string*>(
JNIEnv* env,
const std::u16string* const& input) {
if (!input) {
return nullptr;
}
return base::android::ConvertUTF16ToJavaString(env, *input);
}
template <>
BASE_EXPORT ScopedJavaLocalRef<jobject> ToJniType<std::u16string_view>(
JNIEnv* env,
const std::u16string_view& input) {
return base::android::ConvertUTF16ToJavaString(env, input);
}
template <>
BASE_EXPORT base::FilePath FromJniType<base::FilePath>(
JNIEnv* env,
const JavaRef<jobject>& input) {
return base::FilePath(base::android::ConvertJavaStringToUTF8(
env, static_cast<jstring>(input.obj())));
}
template <>
BASE_EXPORT ScopedJavaLocalRef<jobject> ToJniType<base::FilePath>(
JNIEnv* env,
const base::FilePath& input) {
return base::android::ConvertUTF8ToJavaString(env, input.value());
}
} // namespace jni_zero

@ -49,4 +49,48 @@ BASE_EXPORT ScopedJavaLocalRef<jstring> ConvertUTF16ToJavaString(
} // namespace android
} // namespace base
namespace jni_zero {
template <>
inline std::string FromJniType<std::string>(JNIEnv* env,
const JavaRef<jobject>& input) {
return base::android::ConvertJavaStringToUTF8(
env, static_cast<jstring>(input.obj()));
}
template <>
inline ScopedJavaLocalRef<jobject> ToJniType<std::string>(
JNIEnv* env,
const std::string& input) {
return base::android::ConvertUTF8ToJavaString(env, input);
}
template <>
inline ScopedJavaLocalRef<jobject> ToJniType<const char>(JNIEnv* env,
const char* input) {
return base::android::ConvertUTF8ToJavaString(env, input);
}
template <>
inline std::u16string FromJniType<std::u16string>(
JNIEnv* env,
const JavaRef<jobject>& input) {
return base::android::ConvertJavaStringToUTF16(
env, static_cast<jstring>(input.obj()));
}
template <>
inline ScopedJavaLocalRef<jobject> ToJniType<std::u16string>(
JNIEnv* env,
const std::u16string& input) {
return base::android::ConvertUTF16ToJavaString(env, input);
}
template <>
inline ScopedJavaLocalRef<jobject> ToJniType<std::u16string_view>(
JNIEnv* env,
const std::u16string_view& input) {
return base::android::ConvertUTF16ToJavaString(env, input);
}
} // namespace jni_zero
#endif // BASE_ANDROID_JNI_STRING_H_

@ -16,6 +16,7 @@
#include "base/time/time.h"
#include "build/robolectric_buildflags.h"
// Must come after all headers that specialize FromJniType() / ToJniType().
#if BUILDFLAG(IS_ROBOLECTRIC)
#include "base/base_robolectric_jni/NativeUmaRecorder_jni.h" // nogncheck
#else

@ -2,12 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/android/jni_android.h"
#include "base/android/jni_string.h"
#include "base/base_jni/PathService_jni.h"
#include "base/files/file_path.h"
#include "base/path_service.h"
#include "base/android/jni_string.h"
#include "base/files/file_path.h"
// Must come after all headers that specialize FromJniType() / ToJniType().
#include "base/base_jni/PathService_jni.h"
namespace base {
namespace android {

@ -2,14 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/metrics/statistics_recorder.h"
#include <string>
#include "base/android/jni_string.h"
#include "base/metrics/histogram_base.h"
#include "base/metrics/statistics_recorder.h"
#include "base/system/sys_info.h"
// Must come after other headers because it uses JSONVerbosityLevel.
// Must come after all headers that specialize FromJniType() / ToJniType().
#include "base/metrics_jni/StatisticsRecorderAndroid_jni.h"
namespace base {

@ -9,7 +9,6 @@
#include <utility>
#include "base/android/jni_string.h"
#include "base/android_runtime_jni_headers/Runnable_jni.h"
#include "base/check.h"
#include "base/compiler_specific.h"
#include "base/functional/bind.h"
@ -20,10 +19,13 @@
#include "base/task/thread_pool.h"
#include "base/task/thread_pool/thread_pool_impl.h"
#include "base/task/thread_pool/thread_pool_instance.h"
#include "base/tasks_jni/TaskRunnerImpl_jni.h"
#include "base/time/time.h"
#include "base/trace_event/base_tracing.h"
// Must come after all headers that specialize FromJniType() / ToJniType().
#include "base/android_runtime_jni_headers/Runnable_jni.h"
#include "base/tasks_jni/TaskRunnerImpl_jni.h"
namespace base {
namespace {

@ -14,40 +14,6 @@
#include "base/base_jni/Token_jni.h"
#endif
namespace jni_zero {
template <>
BASE_EXPORT base::Token FromJniType<base::Token>(
JNIEnv* env,
const JavaRef<jobject>& j_object) {
return base::android::TokenAndroid::FromJavaToken(env, j_object);
}
template <>
BASE_EXPORT std::optional<base::Token> FromJniType<std::optional<base::Token>>(
JNIEnv* env,
const JavaRef<jobject>& j_object) {
if (!j_object) {
return std::nullopt;
}
return base::android::TokenAndroid::FromJavaToken(env, j_object);
}
template <>
BASE_EXPORT ScopedJavaLocalRef<jobject> ToJniType<base::Token>(
JNIEnv* env,
const base::Token& token) {
return base::android::TokenAndroid::Create(env, token);
}
template <>
BASE_EXPORT ScopedJavaLocalRef<jobject> ToJniType<std::optional<base::Token>>(
JNIEnv* env,
const std::optional<base::Token>& token) {
if (!token) {
return nullptr;
}
return base::android::TokenAndroid::Create(env, token.value());
}
} // namespace jni_zero
namespace base::android {
ScopedJavaLocalRef<jobject> TokenAndroid::Create(JNIEnv* env,

@ -33,4 +33,18 @@ class BASE_EXPORT TokenAndroid {
} // namespace base::android
namespace jni_zero {
template <>
inline base::Token FromJniType<base::Token>(JNIEnv* env,
const JavaRef<jobject>& j_object) {
return base::android::TokenAndroid::FromJavaToken(env, j_object);
}
template <>
inline ScopedJavaLocalRef<jobject> ToJniType<base::Token>(
JNIEnv* env,
const base::Token& token) {
return base::android::TokenAndroid::Create(env, token);
}
} // namespace jni_zero
#endif // BASE_ANDROID_TOKEN_ANDROID_H_

@ -6,6 +6,7 @@
#include "build/robolectric_buildflags.h"
// Must come after all headers that specialize FromJniType() / ToJniType().
#if BUILDFLAG(IS_ROBOLECTRIC)
#include "base/base_robolectric_jni/TokenBase_jni.h" // nogncheck
#include "base/base_robolectric_jni/UnguessableToken_jni.h" // nogncheck
@ -14,44 +15,6 @@
#include "base/base_jni/UnguessableToken_jni.h"
#endif
namespace jni_zero {
template <>
BASE_EXPORT base::UnguessableToken FromJniType<base::UnguessableToken>(
JNIEnv* env,
const JavaRef<jobject>& j_object) {
return base::android::UnguessableTokenAndroid::FromJavaUnguessableToken(
env, j_object);
}
template <>
BASE_EXPORT std::optional<base::UnguessableToken>
FromJniType<std::optional<base::UnguessableToken>>(
JNIEnv* env,
const JavaRef<jobject>& j_object) {
if (!j_object) {
return std::nullopt;
}
return base::android::UnguessableTokenAndroid::FromJavaUnguessableToken(
env, j_object);
}
template <>
BASE_EXPORT ScopedJavaLocalRef<jobject> ToJniType<base::UnguessableToken>(
JNIEnv* env,
const base::UnguessableToken& token) {
return base::android::UnguessableTokenAndroid::Create(env, token);
}
template <>
BASE_EXPORT ScopedJavaLocalRef<jobject>
ToJniType<std::optional<base::UnguessableToken>>(
JNIEnv* env,
const std::optional<base::UnguessableToken>& token) {
if (!token) {
return nullptr;
}
return base::android::UnguessableTokenAndroid::Create(env, token.value());
}
} // namespace jni_zero
namespace base {
namespace android {

@ -39,4 +39,21 @@ class BASE_EXPORT UnguessableTokenAndroid {
} // namespace android
} // namespace base
namespace jni_zero {
template <>
inline base::UnguessableToken FromJniType<base::UnguessableToken>(
JNIEnv* env,
const JavaRef<jobject>& j_object) {
return base::android::UnguessableTokenAndroid::FromJavaUnguessableToken(
env, j_object);
}
template <>
inline ScopedJavaLocalRef<jobject> ToJniType<base::UnguessableToken>(
JNIEnv* env,
const base::UnguessableToken& token) {
return base::android::UnguessableTokenAndroid::Create(env, token);
}
} // namespace jni_zero
#endif // BASE_ANDROID_UNGUESSABLE_TOKEN_ANDROID_H_

@ -4,23 +4,19 @@
#include "base/files/file_util.h"
#include "base/android/jni_android.h"
#include "base/android/jni_string.h"
#include "base/base_jni/FileUtils_jni.h"
#include "base/files/file_path.h"
#include "base/path_service.h"
using base::android::JavaParamRef;
using base::android::JavaRef;
using base::android::ScopedJavaLocalRef;
// Must come after all headers that specialize FromJniType() / ToJniType().
#include "base/base_jni/FileUtils_jni.h"
namespace base {
namespace android {
static base::FilePath JNI_FileUtils_GetAbsoluteFilePath(
JNIEnv* env,
base::FilePath& file_path) {
return MakeAbsoluteFilePath(file_path);
static std::string JNI_FileUtils_GetAbsoluteFilePath(JNIEnv* env,
std::string& file_path) {
return MakeAbsoluteFilePath(base::FilePath(file_path)).value();
}
} // namespace android

@ -9,7 +9,6 @@
#include "base/android/jni_string.h"
#include "base/check.h"
#include "chrome/android/chrome_jni_headers/DisplayAgent_jni.h"
#include "chrome/browser/android/profile_key_util.h"
#include "chrome/browser/notifications/scheduler/notification_schedule_service_factory.h"
#include "chrome/browser/notifications/scheduler/public/notification_schedule_service.h"
@ -18,6 +17,8 @@
#include "chrome/browser/profiles/profile_key.h"
#include "ui/gfx/android/java_bitmap.h"
// Must come after all headers that specialize FromJniType() / ToJniType().
#include "chrome/android/chrome_jni_headers/DisplayAgent_jni.h"
using base::android::JavaParamRef;
using base::android::ScopedJavaLocalRef;

@ -12,7 +12,6 @@
#include "base/android/jni_android.h"
#include "base/android/jni_array.h"
#include "base/android/jni_string.h"
#include "chrome/browser/optimization_guide/android/jni_headers/OptimizationGuideBridge_jni.h"
#include "chrome/browser/optimization_guide/chrome_hints_manager.h"
#include "chrome/browser/optimization_guide/optimization_guide_keyed_service.h"
#include "chrome/browser/optimization_guide/optimization_guide_keyed_service_factory.h"
@ -24,6 +23,9 @@
#include "url/android/gurl_android.h"
#include "url/gurl.h"
// Must come after all headers that specialize FromJniType() / ToJniType().
#include "chrome/browser/optimization_guide/android/jni_headers/OptimizationGuideBridge_jni.h"
using base::android::AttachCurrentThread;
using base::android::ConvertJavaStringToUTF8;
using base::android::JavaArrayOfByteArrayToBytesVector;

@ -585,4 +585,19 @@ struct ProfileCompare {
std::ostream& operator<<(std::ostream& out,
const Profile::OTRProfileID& profile_id);
#if BUILDFLAG(IS_ANDROID)
namespace jni_zero {
template <>
inline Profile* FromJniType<Profile*>(JNIEnv* env,
const JavaRef<jobject>& j_profile) {
return Profile::FromJavaObject(j_profile);
}
template <>
inline ScopedJavaLocalRef<jobject> ToJniType<Profile>(JNIEnv* env,
const Profile& profile) {
return profile.GetJavaObject();
}
} // namespace jni_zero
#endif // BUILDFLAG(IS_ANDROID)
#endif // CHROME_BROWSER_PROFILES_PROFILE_H_

@ -19,23 +19,6 @@ using jni_zero::JavaParamRef;
using jni_zero::JavaRef;
using jni_zero::ScopedJavaLocalRef;
namespace jni_zero {
template <>
Profile* FromJniType<Profile*>(JNIEnv* env, const JavaRef<jobject>& j_profile) {
return Profile::FromJavaObject(j_profile);
}
template <>
ScopedJavaLocalRef<jobject> ToJniType<Profile*>(JNIEnv* env,
Profile* const& profile) {
if (!profile) {
return nullptr;
}
return profile->GetJavaObject();
}
} // namespace jni_zero
// static
Profile* Profile::FromJavaObject(const JavaRef<jobject>& obj) {

@ -108,6 +108,7 @@ source_set("android") {
deps = [
":jni_headers",
"//chrome/browser/profiles:profile",
"//chrome/browser/ui",
"//chrome/common:constants",
"//components/content_settings/core/common",

@ -8,11 +8,11 @@
#include <vector>
#include "base/android/jni_string.h"
#include "base/android/scoped_java_ref.h"
#include "base/check.h"
#include "base/time/time.h"
#include "chrome/browser/safety_hub/android/jni_headers/PermissionsData_jni.h"
#include "chrome/browser/safety_hub/android/jni_headers/UnusedSitePermissionsBridge_jni.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/safety_hub/unused_site_permissions_service.h"
#include "chrome/browser/ui/safety_hub/unused_site_permissions_service_factory.h"
#include "components/content_settings/core/common/content_settings_constraints.h"
@ -21,20 +21,9 @@
#include "url/gurl.h"
#include "url/origin.h"
namespace jni_zero {
template <>
PermissionsData FromJniType<PermissionsData>(JNIEnv* env,
const JavaRef<jobject>& jobject) {
return FromJavaPermissionsData(env, jobject);
}
template <>
ScopedJavaLocalRef<jobject> ToJniType(JNIEnv* env, const PermissionsData& obj) {
return ToJavaPermissionsData(env, obj);
}
} // namespace jni_zero
// Must come after all headers that specialize FromJniType() / ToJniType().
#include "chrome/browser/safety_hub/android/jni_headers/PermissionsData_jni.h"
#include "chrome/browser/safety_hub/android/jni_headers/UnusedSitePermissionsBridge_jni.h"
PermissionsData FromJavaPermissionsData(
JNIEnv* env,

@ -36,4 +36,21 @@ void RestoreRevokedPermissionsReviewList(
Profile* profile,
std::vector<PermissionsData>& permissions_data_list);
namespace jni_zero {
template <>
inline PermissionsData FromJniType<PermissionsData>(
JNIEnv* env,
const JavaRef<jobject>& jobject) {
return FromJavaPermissionsData(env, jobject);
}
template <>
inline ScopedJavaLocalRef<jobject> ToJniType(JNIEnv* env,
const PermissionsData& obj) {
return ToJavaPermissionsData(env, obj);
}
} // namespace jni_zero
#endif // CHROME_BROWSER_SAFETY_HUB_ANDROID_UNUSED_SITE_PERMISSIONS_BRIDGE_H_

@ -13,10 +13,12 @@
#include "base/memory/raw_ref.h"
#include "components/android_autofill/browser/android_autofill_provider.h"
#include "components/android_autofill/browser/form_data_android.h"
#include "components/android_autofill/browser/jni_headers/AutofillProvider_jni.h"
#include "content/public/browser/web_contents.h"
#include "ui/gfx/geometry/rect_f.h"
// Must come after all headers that specialize FromJniType() / ToJniType().
#include "components/android_autofill/browser/jni_headers/AutofillProvider_jni.h"
namespace autofill {
using base::android::AttachCurrentThread;

@ -7,19 +7,20 @@
#include <memory>
#include <vector>
#include "base/android/jni_string.h"
#include "base/android/jni_weak_ref.h"
#include "base/android/scoped_java_ref.h"
#include "base/containers/span.h"
#include "components/android_autofill/browser/form_field_data_android.h"
#include "components/android_autofill/browser/jni_headers/FormData_jni.h"
#include "components/autofill/core/common/form_data.h"
// Must come after all headers that specialize FromJniType() / ToJniType().
#include "components/android_autofill/browser/jni_headers/FormData_jni.h"
namespace autofill {
namespace {
using base::android::AttachCurrentThread;
using base::android::ScopedJavaLocalRef;
using jni_zero::ScopedJavaLocalRef;
} // namespace
@ -27,12 +28,11 @@ FormDataAndroidBridgeImpl::FormDataAndroidBridgeImpl() = default;
FormDataAndroidBridgeImpl::~FormDataAndroidBridgeImpl() = default;
base::android::ScopedJavaLocalRef<jobject>
FormDataAndroidBridgeImpl::GetOrCreateJavaPeer(
ScopedJavaLocalRef<jobject> FormDataAndroidBridgeImpl::GetOrCreateJavaPeer(
const FormData& form,
SessionId session_id,
base::span<const std::unique_ptr<FormFieldDataAndroid>> fields_android) {
JNIEnv* env = AttachCurrentThread();
JNIEnv* env = jni_zero::AttachCurrentThread();
if (ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); !obj.is_null()) {
return obj;
}

@ -4,18 +4,17 @@
#include "components/download/internal/common/in_memory_download_file.h"
#include "base/android/jni_android.h"
#include "base/android/jni_string.h"
#include "base/files/file_util.h"
#include "base/functional/bind.h"
#include "base/process/process_handle.h"
#include "base/strings/stringprintf.h"
#include "base/task/sequenced_task_runner.h"
#include "components/download/internal/common/jni_headers/InMemoryDownloadFile_jni.h"
#include "components/download/public/common/download_destination_observer.h"
#include "crypto/secure_hash.h"
using base::android::ConvertUTF8ToJavaString;
// Must come after all headers that specialize FromJniType() / ToJniType().
#include "components/download/internal/common/jni_headers/InMemoryDownloadFile_jni.h"
namespace download {
namespace {

@ -21,11 +21,13 @@
#include "base/unguessable_token.h"
#include "components/paint_preview/browser/paint_preview_base_service.h"
#include "components/paint_preview/player/android/convert_to_java_bitmap.h"
#include "components/paint_preview/player/android/jni_headers/PlayerCompositorDelegateImpl_jni.h"
#include "components/services/paint_preview_compositor/public/mojom/paint_preview_compositor.mojom.h"
#include "ui/gfx/geometry/rect.h"
#include "url/gurl.h"
// Must come after all headers that specialize FromJniType() / ToJniType().
#include "components/paint_preview/player/android/jni_headers/PlayerCompositorDelegateImpl_jni.h"
using base::android::JavaParamRef;
using base::android::ScopedJavaGlobalRef;
using base::android::ScopedJavaLocalRef;

@ -6,25 +6,17 @@
#include <string>
#include "components/prefs/android/jni_headers/PrefService_jni.h"
#include "base/android/jni_string.h"
#include "components/prefs/pref_service.h"
#include "components/prefs/prefs_export.h"
using base::android::JavaParamRef;
using base::android::JavaRef;
using base::android::ScopedJavaLocalRef;
// Must come after all headers that specialize FromJniType() / ToJniType().
#include "components/prefs/android/jni_headers/PrefService_jni.h"
using jni_zero::AttachCurrentThread;
namespace jni_zero {
template <>
COMPONENTS_PREFS_EXPORT PrefService* FromJniType<PrefService*>(
JNIEnv* env,
const JavaRef<jobject>& obj) {
return PrefServiceAndroid::FromPrefServiceAndroid(obj);
}
} // namespace jni_zero
using jni_zero::JavaParamRef;
using jni_zero::JavaRef;
using jni_zero::ScopedJavaLocalRef;
PrefServiceAndroid::PrefServiceAndroid(PrefService* pref_service)
: pref_service_(pref_service) {}

@ -5,10 +5,7 @@
#ifndef COMPONENTS_PREFS_ANDROID_PREF_SERVICE_ANDROID_H_
#define COMPONENTS_PREFS_ANDROID_PREF_SERVICE_ANDROID_H_
#include <jni.h>
#include "base/android/jni_string.h"
#include "base/android/scoped_java_ref.h"
#include "base/android/jni_android.h"
#include "base/memory/raw_ptr.h"
#include "components/prefs/prefs_export.h"
@ -67,4 +64,12 @@ class COMPONENTS_PREFS_EXPORT PrefServiceAndroid {
base::android::ScopedJavaGlobalRef<jobject> java_ref_;
};
namespace jni_zero {
template <>
inline PrefService* FromJniType<PrefService*>(JNIEnv* env,
const JavaRef<jobject>& obj) {
return PrefServiceAndroid::FromPrefServiceAndroid(obj);
}
} // namespace jni_zero
#endif // COMPONENTS_PREFS_ANDROID_PREF_SERVICE_ANDROID_H_

@ -7,11 +7,12 @@
#include <memory>
#include <string>
#include "base/android/jni_array.h"
#include "base/android/jni_string.h"
#include "components/query_tiles/jni_headers/TileConversionBridge_jni.h"
#include "url/android/gurl_android.h"
// Must come after all headers that specialize FromJniType() / ToJniType().
#include "components/query_tiles/jni_headers/TileConversionBridge_jni.h"
namespace query_tiles {
ScopedJavaLocalRef<jobject> CreateJavaTileAndMaybeAddToList(

@ -10,6 +10,7 @@ include_rules = [
"+services/metrics/public",
"+services/network/public/cpp/shared_url_loader_factory.h",
"+sql",
"+third_party/jni_zero",
"+third_party/perfetto",
"+third_party/tflite",
"+third_party/tflite_support",

@ -63,7 +63,7 @@ void JavaGURLArrayToGURLVector(
JNIEnv* env,
const base::android::JavaRef<jobjectArray>& j_gurls,
std::vector<GURL>* ret) {
*ret = jni_zero::ConvertArray<std::vector<GURL>>::FromJniType(env, j_gurls);
*ret = jni_zero::FromJniArray<std::vector<GURL>>(env, j_gurls);
}
static void JavaLongArrayToBaseTimeVector(

@ -7,17 +7,17 @@
#include <array>
#include <cstdint>
#include <string>
#include "base/android/jni_android.h"
#include "base/android/jni_array.h"
#include "base/android/scoped_java_ref.h"
#include "base/time/time.h"
#include "components/segmentation_platform/public/input_context.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/jni_zero/default_conversions.h"
#include "url/android/gurl_android.h"
#include "url/gurl.h"
#include <jni.h>
namespace segmentation_platform {
class InputContextAndroidTest : public testing::Test {
@ -108,8 +108,7 @@ TEST_F(InputContextAndroidTest, FromJavaParams) {
base::android::ScopedJavaLocalRef<jobjectArray> java_url_keys =
base::android::ToJavaArrayOfStrings(jni_env, url_keys);
base::android::ScopedJavaLocalRef<jobjectArray> java_url_values =
jni_zero::ConvertArray<std::vector<base::android::ScopedJavaLocalRef<
jobject>>>::ToJniType(jni_env, url_values, jni_zero::g_object_class);
jni_zero::ToJniArray(jni_env, url_values, jni_zero::g_object_class);
segmentation_platform::InputContextAndroid::FromJavaParams(
jni_env, reinterpret_cast<intptr_t>(native_input_context.get()),

@ -17,7 +17,7 @@
#include "components/supervised_user/core/common/supervised_user_constants.h"
#if BUILDFLAG(IS_ANDROID)
#include "components/prefs/pref_service.h"
#include "components/prefs/android/pref_service_android.h"
// Must come after other includes, because FromJniType() uses PrefService.
#include "components/supervised_user/android/supervised_user_preferences_jni_headers/SupervisedUserPreferences_jni.h"

@ -4,8 +4,11 @@
#include "content/browser/android/additional_navigation_params_utils.h"
#include "base/android/jni_string.h"
#include "base/android/unguessable_token_android.h"
#include "base/numerics/safe_conversions.h"
// Must come after all headers that specialize FromJniType() / ToJniType().
#include "content/public/android/content_jni_headers/AdditionalNavigationParamsUtils_jni.h"
namespace content {

@ -4,7 +4,6 @@
#include "content/browser/attribution_reporting/attribution_os_level_manager_android.h"
#include <jni.h>
#include <stddef.h>
#include <iterator>
@ -13,8 +12,7 @@
#include <utility>
#include <vector>
#include "base/android/jni_array.h"
#include "base/android/scoped_java_ref.h"
#include "base/android/jni_string.h"
#include "base/barrier_closure.h"
#include "base/check.h"
#include "base/check_op.h"
@ -45,6 +43,9 @@
#include "url/gurl.h"
#include "url/origin.h"
using jni_zero::AttachCurrentThread;
using jni_zero::ScopedJavaLocalRef;
namespace content {
namespace {
@ -98,8 +99,7 @@ ApiState ConvertToApiState(int value) {
void GetMeasurementApiStatus() {
base::ElapsedThreadTimer timer;
Java_AttributionOsLevelManager_getMeasurementApiStatus(
base::android::AttachCurrentThread());
Java_AttributionOsLevelManager_getMeasurementApiStatus(AttachCurrentThread());
if (timer.is_supported()) {
base::UmaHistogramTimes("Conversions.GetMeasurementStatusTime",
timer.Elapsed());
@ -125,7 +125,7 @@ static void JNI_AttributionOsLevelManager_OnMeasurementStateReturned(
AttributionOsLevelManagerAndroid::AttributionOsLevelManagerAndroid() {
jobj_ = Java_AttributionOsLevelManager_Constructor(
base::android::AttachCurrentThread(), reinterpret_cast<intptr_t>(this));
AttachCurrentThread(), reinterpret_cast<intptr_t>(this));
if (AttributionOsLevelManager::ShouldInitializeApiState()) {
base::ThreadPool::CreateSequencedTaskRunner({base::MayBlock()})
@ -135,8 +135,7 @@ AttributionOsLevelManagerAndroid::AttributionOsLevelManagerAndroid() {
AttributionOsLevelManagerAndroid::~AttributionOsLevelManagerAndroid() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
Java_AttributionOsLevelManager_nativeDestroyed(
base::android::AttachCurrentThread(), jobj_);
Java_AttributionOsLevelManager_nativeDestroyed(AttachCurrentThread(), jobj_);
}
namespace {
@ -175,11 +174,11 @@ void AttributionOsLevelManagerAndroid::Register(
const size_t num_items = registration.registration_items.size();
CHECK_EQ(num_items, is_debug_key_allowed.size());
JNIEnv* env = base::android::AttachCurrentThread();
JNIEnv* env = AttachCurrentThread();
Registrar registrar = registration.registrar;
attribution_reporting::mojom::RegistrationType type = registration.GetType();
std::vector<base::android::ScopedJavaLocalRef<jobject>> registration_urls;
std::vector<ScopedJavaLocalRef<jobject>> registration_urls;
base::ranges::transform(
registration.registration_items, std::back_inserter(registration_urls),
[env](const attribution_reporting::OsRegistrationItem& item) {
@ -277,9 +276,9 @@ void AttributionOsLevelManagerAndroid::ClearData(
base::OnceClosure done) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
JNIEnv* env = base::android::AttachCurrentThread();
JNIEnv* env = AttachCurrentThread();
std::vector<base::android::ScopedJavaLocalRef<jobject>> j_origins;
std::vector<ScopedJavaLocalRef<jobject>> j_origins;
base::ranges::transform(
origins, std::back_inserter(j_origins), [env](const url::Origin& origin) {
return url::GURLAndroid::FromNativeGURL(env, origin.GetURL());

@ -30,10 +30,11 @@
#include "third_party/blink/public/common/page/page_zoom.h"
#if BUILDFLAG(IS_ANDROID)
#include "base/android/jni_array.h"
#include "content/public/android/content_jni_headers/HostZoomMapImpl_jni.h"
#include "base/android/jni_string.h"
#include "content/public/browser/android/browser_context_handle.h"
using base::android::ScopedJavaLocalRef;
// Must come after all headers that specialize FromJniType() / ToJniType().
#include "content/public/android/content_jni_headers/HostZoomMapImpl_jni.h"
#endif
namespace content {
@ -186,7 +187,7 @@ double HostZoomMapImpl::GetZoomLevelForHostAndSchemeAndroid(
// method will return the adjusted zoom level considering OS settings. Note
// that the OS |fontScale| will be factored in only when the Page Zoom feature
// is enabled.
JNIEnv* env = base::android::AttachCurrentThread();
JNIEnv* env = jni_zero::AttachCurrentThread();
double adjusted_zoom_level =
Java_HostZoomMapImpl_getAdjustedZoomLevel(env, zoom_level);
return adjusted_zoom_level;
@ -512,7 +513,7 @@ void HostZoomMapImpl::SetClockForTesting(base::Clock* clock) {
#if BUILDFLAG(IS_ANDROID)
void HostZoomMapImpl::SetSystemFontScaleForTesting(float scale) {
JNIEnv* env = base::android::AttachCurrentThread();
JNIEnv* env = jni_zero::AttachCurrentThread();
Java_HostZoomMapImpl_setSystemFontScaleForTesting(env, scale); // IN-TEST
}
@ -619,12 +620,12 @@ jdouble JNI_HostZoomMapImpl_GetDefaultZoomLevel(
return host_zoom_map->GetDefaultZoomLevel();
}
std::vector<ScopedJavaLocalRef<jobject>>
std::vector<jni_zero::ScopedJavaLocalRef<jobject>>
JNI_HostZoomMapImpl_GetAllHostZoomLevels(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& j_context) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
std::vector<ScopedJavaLocalRef<jobject>> ret;
std::vector<jni_zero::ScopedJavaLocalRef<jobject>> ret;
// Get instance of HostZoomMap.
BrowserContext* context = BrowserContextFromJavaHandle(j_context);

@ -17,10 +17,14 @@ config("toolchain_define") {
# This is the public target that we intend others to use.
component("jni_zero") {
# This is the public API.
sources = [ "jni_zero.h" ]
sources = [
"default_conversions.h",
"jni_zero.h",
]
# These are intended to only be used within jni_zero and the code it generates.
sources += [
"default_conversions.cc",
"jni_export.h",
"jni_zero.cc",
"jni_zero_internal.h",

@ -7,31 +7,6 @@ from codegen import header_common
import java_types
def conversion_declarations(java_to_cpp_types, cpp_to_java_types):
declarations = set()
for java_type in java_to_cpp_types:
T = java_type.converted_type()
declarations.add(f'template<> {T} '
f'FromJniType<{T}>(JNIEnv*, const JavaRef<jobject>&);')
for java_type in cpp_to_java_types:
T = java_type.converted_type()
declarations.add(f'template<> jni_zero::ScopedJavaLocalRef<jobject> '
f'ToJniType<{T}>(JNIEnv*, {T} const&);')
if not declarations:
return ''
declaration_lines = '\n'.join(sorted(declarations))
return f"""\
// Forward declare used conversion functions to avoid a compiler warning that
// triggers if a conversion specialization exists within the including .cc file.
namespace jni_zero {{
{declaration_lines}
}} // namespace jni_zero
"""
def to_jni_expression(sb, rvalue, java_type, clazz_param=None):
"""Writes a ToJniType() expression to |sb|.
@ -40,14 +15,13 @@ def to_jni_expression(sb, rvalue, java_type, clazz_param=None):
java_type: Type containing the @JniType annotation.
clazz_param: Snippet to use as the third parameter for array conversions.
"""
T = java_type.converted_type()
assert T
assert java_type.converted_type()
if java_type.is_primitive():
sb(f'static_cast<{java_type.to_cpp()}>({rvalue})')
return
if not java_type.is_array():
sb(f'jni_zero::ToJniType<{T}>')
sb(f'jni_zero::ToJniType')
sb.param_list(['env', rvalue])
return
@ -55,8 +29,8 @@ def to_jni_expression(sb, rvalue, java_type, clazz_param=None):
if element_type.is_array():
raise Exception(
'@JniType() for multi-dimensional arrays are not yet supported. '
'Found ' + T)
sb(f'jni_zero::ConvertArray<{T}>::ToJniType')
'Found ' + java_type.converted_type())
sb(f'jni_zero::ToJniArray')
with sb.param_list() as plist:
plist += ['env', rvalue]
if not element_type.is_primitive():
@ -113,5 +87,5 @@ def from_jni_expression(sb, rvalue, java_type, release_ref=False):
raise Exception(
'@JniType() for multi-dimensional arrays are not yet supported. '
'Found ' + T)
sb(f'jni_zero::ConvertArray<{T}>::FromJniType')
sb(f'jni_zero::FromJniArray<{T}>')
sb.param_list(['env', rvalue])

@ -0,0 +1,84 @@
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/jni_zero/default_conversions.h"
namespace jni_zero {
// Specialization for int64_t.
template <>
std::vector<int64_t> FromJniArray<std::vector<int64_t>>(
JNIEnv* env,
const JavaRef<jobject>& j_object) {
jlongArray j_array = static_cast<jlongArray>(j_object.obj());
jsize array_jsize = env->GetArrayLength(j_array);
size_t array_size = static_cast<size_t>(array_jsize);
std::vector<int64_t> ret;
ret.resize(array_size);
env->GetLongArrayRegion(j_array, 0, array_jsize, ret.data());
return ret;
}
template <>
ScopedJavaLocalRef<jarray> ToJniArray<std::vector<int64_t>>(
JNIEnv* env,
const std::vector<int64_t>& vec) {
jsize array_jsize = static_cast<jsize>(vec.size());
jlongArray jia = env->NewLongArray(array_jsize);
CheckException(env);
env->SetLongArrayRegion(jia, 0, array_jsize, vec.data());
return ScopedJavaLocalRef<jarray>(env, jia);
}
// Specialization for int32_t.
template <>
std::vector<int32_t> FromJniArray<std::vector<int32_t>>(
JNIEnv* env,
const JavaRef<jobject>& j_object) {
jintArray j_array = static_cast<jintArray>(j_object.obj());
jsize array_jsize = env->GetArrayLength(j_array);
size_t array_size = static_cast<size_t>(array_jsize);
std::vector<int32_t> ret;
ret.resize(array_size);
env->GetIntArrayRegion(j_array, 0, array_jsize, ret.data());
return ret;
}
template <>
ScopedJavaLocalRef<jarray> ToJniArray<std::vector<int32_t>>(
JNIEnv* env,
const std::vector<int32_t>& vec) {
jsize array_jsize = static_cast<jsize>(vec.size());
jintArray jia = env->NewIntArray(array_jsize);
CheckException(env);
env->SetIntArrayRegion(jia, 0, array_jsize, vec.data());
return ScopedJavaLocalRef<jarray>(env, jia);
}
// Specialization for byte array.
template <>
std::vector<uint8_t> FromJniArray<std::vector<uint8_t>>(
JNIEnv* env,
const JavaRef<jobject>& j_object) {
jbyteArray j_array = static_cast<jbyteArray>(j_object.obj());
jsize array_jsize = env->GetArrayLength(j_array);
size_t array_size = static_cast<size_t>(array_jsize);
std::vector<uint8_t> ret;
ret.resize(array_size);
env->GetByteArrayRegion(j_array, 0, array_jsize,
reinterpret_cast<jbyte*>(ret.data()));
return ret;
}
template <>
ScopedJavaLocalRef<jarray> ToJniArray<std::vector<uint8_t>>(
JNIEnv* env,
const std::vector<uint8_t>& vec) {
jsize array_jsize = static_cast<jsize>(vec.size());
jbyteArray jia = env->NewByteArray(array_jsize);
CheckException(env);
env->SetByteArrayRegion(jia, 0, array_jsize,
reinterpret_cast<const jbyte*>(vec.data()));
return ScopedJavaLocalRef<jarray>(env, jia);
}
} // namespace jni_zero

@ -0,0 +1,157 @@
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef JNI_ZERO_DEFAULT_CONVERSIONS_H_
#define JNI_ZERO_DEFAULT_CONVERSIONS_H_
#include <optional>
#include "third_party/jni_zero/jni_zero.h"
namespace jni_zero {
namespace internal {
template <typename T>
concept HasReserve = requires(T t) { t.reserve(0); };
template <typename T>
concept HasPushBack = requires(T t, T::value_type v) { t.push_back(v); };
template <typename T>
concept HasInsert = requires(T t, T::value_type v) { t.insert(v); };
template <typename T>
concept IsContainer = requires(T t) {
typename T::value_type;
t.begin();
t.end();
t.size();
};
template <typename T>
concept IsObjectContainer =
IsContainer<T> && !std::is_arithmetic_v<typename T::value_type>;
template <typename T>
concept IsOptional = std::same_as<T, std::optional<typename T::value_type>>;
} // namespace internal
// Allow conversions using std::optional by wrapping non-optional conversions.
template <internal::IsOptional T>
inline T FromJniType(JNIEnv* env, const JavaRef<jobject>& j_object) {
if (!j_object) {
return std::nullopt;
}
return FromJniType<typename T::value_type>(env, j_object);
}
template <internal::IsOptional T>
inline ScopedJavaLocalRef<jobject> ToJniType(JNIEnv* env, const T& opt_value) {
if (!opt_value) {
return nullptr;
}
return ToJniType(env, opt_value.value());
}
// Convert Java array -> container type using FromJniType() on each element.
template <internal::IsObjectContainer ContainerType>
inline ContainerType FromJniArray(JNIEnv* env,
const JavaRef<jobject>& j_object) {
jobjectArray j_array = static_cast<jobjectArray>(j_object.obj());
using ElementType = std::remove_const_t<typename ContainerType::value_type>;
constexpr bool has_push_back = internal::HasPushBack<ContainerType>;
constexpr bool has_insert = internal::HasInsert<ContainerType>;
static_assert(has_push_back || has_insert, "Template type not supported.");
jsize array_jsize = env->GetArrayLength(j_array);
ContainerType ret;
if constexpr (internal::HasReserve<ContainerType>) {
size_t array_size = static_cast<size_t>(array_jsize);
ret.reserve(array_size);
}
for (jsize i = 0; i < array_jsize; ++i) {
jobject j_element = env->GetObjectArrayElement(j_array, i);
// Do not call FromJni for jobject->jobject.
if constexpr (std::is_base_of_v<JavaRef<jobject>, ElementType>) {
if constexpr (has_push_back) {
ret.emplace_back(env, j_element);
} else if constexpr (has_insert) {
ret.emplace(env, j_element);
}
} else {
auto element = ScopedJavaLocalRef<jobject>::Adopt(env, j_element);
if constexpr (has_push_back) {
ret.push_back(FromJniType<ElementType>(env, element));
} else if constexpr (has_insert) {
ret.insert(FromJniType<ElementType>(env, element));
}
}
}
return ret;
}
// Convert container type -> Java array using ToJniType() on each element.
template <internal::IsObjectContainer ContainerType>
inline ScopedJavaLocalRef<jobjectArray>
ToJniArray(JNIEnv* env, const ContainerType& collection, jclass clazz) {
using ElementType = std::remove_const_t<typename ContainerType::value_type>;
size_t array_size = collection.size();
jsize array_jsize = static_cast<jsize>(array_size);
jobjectArray j_array = env->NewObjectArray(array_jsize, clazz, nullptr);
CheckException(env);
jsize i = 0;
for (auto& value : collection) {
// Do not call ToJni for jobject->jobject.
if constexpr (std::is_base_of_v<JavaRef<jobject>, ElementType>) {
env->SetObjectArrayElement(j_array, i, value.obj());
} else {
ScopedJavaLocalRef<jobject> element = ToJniType(env, value);
env->SetObjectArrayElement(j_array, i, element.obj());
}
++i;
}
return ScopedJavaLocalRef<jobjectArray>(env, j_array);
}
// Specialization for int64_t.
template <>
JNI_ZERO_COMPONENT_BUILD_EXPORT std::vector<int64_t>
FromJniArray<std::vector<int64_t>>(JNIEnv* env,
const JavaRef<jobject>& j_object);
template <>
JNI_ZERO_COMPONENT_BUILD_EXPORT ScopedJavaLocalRef<jarray>
ToJniArray<std::vector<int64_t>>(JNIEnv* env, const std::vector<int64_t>& vec);
// Specialization for int32_t.
template <>
JNI_ZERO_COMPONENT_BUILD_EXPORT std::vector<int32_t>
FromJniArray<std::vector<int32_t>>(JNIEnv* env,
const JavaRef<jobject>& j_object);
template <>
JNI_ZERO_COMPONENT_BUILD_EXPORT ScopedJavaLocalRef<jarray>
ToJniArray<std::vector<int32_t>>(JNIEnv* env, const std::vector<int32_t>& vec);
// Specialization for byte array.
template <>
JNI_ZERO_COMPONENT_BUILD_EXPORT std::vector<uint8_t>
FromJniArray<std::vector<uint8_t>>(JNIEnv* env,
const JavaRef<jobject>& j_object);
template <>
JNI_ZERO_COMPONENT_BUILD_EXPORT ScopedJavaLocalRef<jarray>
ToJniArray<std::vector<uint8_t>>(JNIEnv* env, const std::vector<uint8_t>& vec);
// Specialization for ByteArrayView.
template <>
inline ByteArrayView FromJniArray<ByteArrayView>(
JNIEnv* env,
const JavaRef<jobject>& j_object) {
jbyteArray j_array = static_cast<jbyteArray>(j_object.obj());
return ByteArrayView(env, j_array);
}
} // namespace jni_zero
#endif // JNI_ZERO_DEFAULT_CONVERSIONS_H_

@ -286,33 +286,6 @@ class JniObject:
return f'Java_{escaped_name}_native{native.cpp_name}'
def _UsesConvertType(java_type):
# Array conversions do not need to be declared and primitive conversions
# are just static_cast.
return bool(java_type.converted_type() and not java_type.is_array()
and not java_type.is_primitive())
def _CollectConvertTypeTypes(natives, called_by_natives):
java_to_cpp_types = []
cpp_to_java_types = []
for native in natives:
java_to_cpp_types.extend(param.java_type for param in native.params
if _UsesConvertType(param.java_type))
if _UsesConvertType(native.return_type):
cpp_to_java_types.append(native.return_type)
for called_by_native in called_by_natives:
cpp_to_java_types.extend(param.java_type
for param in called_by_native.params
if _UsesConvertType(param.java_type))
if _UsesConvertType(called_by_native.return_type):
java_to_cpp_types.append(called_by_native.return_type)
return java_to_cpp_types, cpp_to_java_types
def _CollectReferencedClasses(jni_obj):
ret = set()
# @CalledByNatives can appear on nested classes, so check each one.
@ -352,7 +325,6 @@ class InlHeaderFileGenerator:
template = Template("""\
${PREAMBLE}\
${CLASS_ACCESSORS}\
${CONVERSION_FUNCTION_DECLARATIONS}\
${OPEN_NAMESPACE}\
${CONSTANTS_ENUMS}\
${NATIVES}\
@ -369,10 +341,6 @@ ${EPILOGUE}\
self.options.extra_includes)
class_accessors = header_common.class_accessors(java_classes,
self.jni_obj.module_name)
java_to_cpp_types, cpp_to_java_types = _CollectConvertTypeTypes(
self.natives, self.called_by_natives)
conversion_declarations = convert_type.conversion_declarations(
java_to_cpp_types, cpp_to_java_types)
constants_enums = called_by_native_header.constants_enums(
self.java_class, self.constant_fields)
@ -384,7 +352,6 @@ ${EPILOGUE}\
'PREAMBLE': preamble,
'EPILOGUE': epilogue,
'CLASS_ACCESSORS': class_accessors,
'CONVERSION_FUNCTION_DECLARATIONS': conversion_declarations,
'CONSTANTS_ENUMS': constants_enums,
'CALLED_BY_NATIVES': called_by_natives_code,
'NATIVES': natives_code,

@ -25,6 +25,11 @@
#define JNI_BOUNDARY_EXPORT extern "C" __attribute__((visibility("default")))
#endif
#if defined(__cpp_concepts) && __cpp_concepts >= 201907L
#define JNI_ZERO_ENABLE_TYPE_CONVERSIONS 1
#else
#define JNI_ZERO_ENABLE_TYPE_CONVERSIONS 0
#endif
// Wrapper used to receive int when calling Java from native.
// The wrapper disallows automatic conversion of long to int.
@ -711,196 +716,69 @@ JNI_ZERO_COMPONENT_BUILD_EXPORT ScopedJavaLocalRef<jclass> GetClass(
JNIEnv* env,
const char* class_name);
// Primary templates for non-Array conversion fuctions. Embedding application
// can specialize these functions for their own custom types in order to use
// custom types in @JniType.
template <typename T>
T FromJniType(JNIEnv*, const JavaRef<jobject>&);
#if JNI_ZERO_ENABLE_TYPE_CONVERSIONS
#define JNI_ZERO_CONVERSION_FAILED_MSG(name) \
"Failed to find a " name \
" specialization for the given type. Did you forget to include the " \
"header file that declares it?\n" \
"If this error originates from a generated _jni.h file, make sure that " \
"the header that declares the specialization is #included before the " \
"_jni.h one."
#else
#define JNI_ZERO_CONVERSION_FAILED_MSG(x) "Use of @JniType requires C++20."
#endif
template <typename T>
ScopedJavaLocalRef<jobject> ToJniType(JNIEnv*, const T&);
// Primary template for Array conversion.
// This is in a struct so that we are able to write a default implementation for
// container of any type as long as there is a conversion function from jobject
// to that type. Partial specialized template functions are not allowed, but
// functions inside a struct are.
template <typename ContainerType>
struct ConvertArray;
#if defined(__cpp_concepts) && __cpp_concepts >= 201907L
namespace internal {
template <typename T>
concept HasReserve = requires(T t) { t.reserve(0); };
inline T FromJniType(JNIEnv* env, const JavaRef<jobject>& obj) {
static_assert(false, JNI_ZERO_CONVERSION_FAILED_MSG("FromJniType"));
}
template <typename T>
concept HasPushBack = requires(T t, T::value_type v) { t.push_back(v); };
inline ScopedJavaLocalRef<jobject> ToJniType(JNIEnv* env, const T& obj) {
static_assert(false, JNI_ZERO_CONVERSION_FAILED_MSG("ToJniType"));
}
// Allow conversions using pointers by wrapping non-pointer conversions.
// Cannot live in default_conversions.h because we want code to be able to
// specialize it.
template <typename T>
inline ScopedJavaLocalRef<jobject> ToJniType(JNIEnv* env, T* value) {
if (!value) {
return nullptr;
}
return ToJniType(env, *value);
}
#if JNI_ZERO_ENABLE_TYPE_CONVERSIONS
#undef JNI_ZERO_CONVERSION_FAILED_MSG
#define JNI_ZERO_CONVERSION_FAILED_MSG(name) \
"Failed to find a " name \
" specialization for the given type.\n" \
"If this error is from a generated _jni.h file, ensure that the type " \
"conforms to the container concepts defined in " \
"jni_zero/default_conversions.h.\n" \
"If this error is from a non-generated call, ensure that there " \
"exists an #include for jni_zero/default_conversions.h."
#endif
template <typename T>
concept HasInsert = requires(T t, T::value_type v) { t.insert(v); };
inline ScopedJavaLocalRef<jobjectArray> ToJniArray(JNIEnv* env,
const T& obj,
jclass array_class) {
static_assert(false, JNI_ZERO_CONVERSION_FAILED_MSG("ToJniArray"));
}
template <typename T>
concept IsContainer = requires(T t) {
typename T::value_type;
t.begin();
t.end();
t.size();
};
inline ScopedJavaLocalRef<jarray> ToJniArray(JNIEnv* env, const T& obj) {
static_assert(false, JNI_ZERO_CONVERSION_FAILED_MSG("ToJniArray"));
}
template <typename T>
concept IsObjectContainer =
IsContainer<T> && !std::is_arithmetic_v<typename T::value_type>;
} // namespace internal
inline T FromJniArray(JNIEnv* env, const JavaRef<jobject>& obj) {
static_assert(false, JNI_ZERO_CONVERSION_FAILED_MSG("FromJniArray"));
}
// Partial specialization for converting java arrays into std containers
template <internal::IsObjectContainer ContainerType>
struct ConvertArray<ContainerType> {
private:
using ElementType = std::remove_const_t<typename ContainerType::value_type>;
public:
static ContainerType FromJniType(JNIEnv* env,
const JavaRef<jobjectArray>& j_array) {
constexpr bool has_push_back = internal::HasPushBack<ContainerType>;
constexpr bool has_insert = internal::HasInsert<ContainerType>;
static_assert(has_push_back || has_insert, "Template type not supported.");
jsize array_jsize = env->GetArrayLength(j_array.obj());
ContainerType ret;
if constexpr (internal::HasReserve<ContainerType>) {
size_t array_size = static_cast<size_t>(array_jsize);
ret.reserve(array_size);
}
for (jsize i = 0; i < array_jsize; ++i) {
jobject j_element = env->GetObjectArrayElement(j_array.obj(), i);
// Do not call FromJniType for jobject->jobject.
if constexpr (std::is_base_of_v<JavaRef<jobject>, ElementType>) {
if constexpr (has_push_back) {
ret.emplace_back(env, j_element);
} else if constexpr (has_insert) {
ret.emplace(env, j_element);
}
} else {
auto element =
jni_zero::ScopedJavaLocalRef<jobject>::Adopt(env, j_element);
if constexpr (has_push_back) {
ret.push_back(jni_zero::FromJniType<ElementType>(env, element));
} else if constexpr (has_insert) {
ret.insert(jni_zero::FromJniType<ElementType>(env, element));
}
}
}
return ret;
}
static ScopedJavaLocalRef<jobjectArray>
ToJniType(JNIEnv* env, const ContainerType& collection, jclass clazz) {
size_t array_size = collection.size();
jsize array_jsize = static_cast<jsize>(array_size);
jobjectArray j_array = env->NewObjectArray(array_jsize, clazz, nullptr);
CheckException(env);
jsize i = 0;
for (auto& value : collection) {
// Do not call ToJniType for jobject->jobject.
if constexpr (std::is_base_of_v<JavaRef<jobject>, ElementType>) {
env->SetObjectArrayElement(j_array, i, value.obj());
} else {
ScopedJavaLocalRef<jobject> element =
jni_zero::ToJniType<ElementType>(env, value);
env->SetObjectArrayElement(j_array, i, element.obj());
}
++i;
}
return ScopedJavaLocalRef<jobjectArray>(env, j_array);
}
};
#endif // defined(__cpp_concepts) && __cpp_concepts >= 202002L
// Specialization for int64_t.
template <>
struct ConvertArray<std::vector<int64_t>> {
static std::vector<int64_t> FromJniType(JNIEnv* env,
const JavaRef<jlongArray>& j_array) {
jsize array_jsize = env->GetArrayLength(j_array.obj());
size_t array_size = static_cast<size_t>(array_jsize);
std::vector<int64_t> ret;
ret.resize(array_size);
env->GetLongArrayRegion(j_array.obj(), 0, array_jsize, ret.data());
return ret;
}
static ScopedJavaLocalRef<jlongArray> ToJniType(
JNIEnv* env,
const std::vector<int64_t>& vec) {
jsize array_jsize = static_cast<jsize>(vec.size());
jlongArray jia = env->NewLongArray(array_jsize);
CheckException(env);
env->SetLongArrayRegion(jia, 0, array_jsize, vec.data());
return ScopedJavaLocalRef<jlongArray>(env, jia);
}
};
// Specialization for int32_t.
template <>
struct ConvertArray<std::vector<int32_t>> {
static std::vector<int32_t> FromJniType(JNIEnv* env,
const JavaRef<jintArray>& j_array) {
jsize array_jsize = env->GetArrayLength(j_array.obj());
size_t array_size = static_cast<size_t>(array_jsize);
std::vector<int32_t> ret;
ret.resize(array_size);
env->GetIntArrayRegion(j_array.obj(), 0, array_jsize, ret.data());
return ret;
}
static ScopedJavaLocalRef<jintArray> ToJniType(
JNIEnv* env,
const std::vector<int32_t>& vec) {
jsize array_jsize = static_cast<jsize>(vec.size());
jintArray jia = env->NewIntArray(array_jsize);
CheckException(env);
env->SetIntArrayRegion(jia, 0, array_jsize, vec.data());
return ScopedJavaLocalRef<jintArray>(env, jia);
}
};
// Specialization for byte array.
template <>
struct ConvertArray<std::vector<uint8_t>> {
static std::vector<uint8_t> FromJniType(JNIEnv* env,
const JavaRef<jbyteArray>& j_array) {
jsize array_jsize = env->GetArrayLength(j_array.obj());
size_t array_size = static_cast<size_t>(array_jsize);
std::vector<uint8_t> ret;
ret.resize(array_size);
env->GetByteArrayRegion(j_array.obj(), 0, array_jsize,
reinterpret_cast<jbyte*>(ret.data()));
return ret;
}
static ScopedJavaLocalRef<jbyteArray> ToJniType(
JNIEnv* env,
const std::vector<uint8_t>& vec) {
jsize array_jsize = static_cast<jsize>(vec.size());
jbyteArray jia = env->NewByteArray(array_jsize);
CheckException(env);
env->SetByteArrayRegion(jia, 0, array_jsize,
reinterpret_cast<const jbyte*>(vec.data()));
return ScopedJavaLocalRef<jbyteArray>(env, jia);
}
};
// Specialization for ByteArrayView.
template <>
struct ConvertArray<ByteArrayView> {
static ByteArrayView FromJniType(JNIEnv* env,
const JavaRef<jbyteArray>& array) {
return ByteArrayView(env, array.obj());
}
};
#undef JNI_ZERO_CONVERSION_FAILED_MSG
// This class is a wrapper for JNIEnv Get(Static)MethodID.
class JNI_ZERO_COMPONENT_BUILD_EXPORT MethodID {

@ -11,6 +11,10 @@
#include "third_party/jni_zero/jni_zero.h"
#include "third_party/jni_zero/logging.h"
#if JNI_ZERO_ENABLE_TYPE_CONVERSIONS
#include "third_party/jni_zero/default_conversions.h"
#endif
// Project-specific macros used by the header files generated by
// jni_generator.py. Different projects can then specify their own
// implementation for this file.

@ -43,6 +43,7 @@ source_set("test_native_side") {
sources = [
"sample_for_tests.cc",
"sample_for_tests.h",
"stub_conversions.h",
]
}

@ -38,13 +38,6 @@ inline jclass org_jni_1zero_SampleForTests_00024InnerStructB_clazz(JNIEnv* env)
}
#endif
// Forward declare used conversion functions to avoid a compiler warning that
// triggers if a conversion specialization exists within the including .cc file.
namespace jni_zero {
template<> jni_zero::ScopedJavaLocalRef<jobject> ToJniType<const char*>(JNIEnv*, const char* const&);
template<> jni_zero::tests::CPPClass* FromJniType<jni_zero::tests::CPPClass*>(JNIEnv*, const JavaRef<jobject>&);
template<> std::string FromJniType<std::string>(JNIEnv*, const JavaRef<jobject>&);
} // namespace jni_zero
namespace jni_zero {
namespace tests {
// Java to native functions
@ -66,7 +59,7 @@ JNI_BOUNDARY_EXPORT void Java_org_jni_1zero_GEN_1JNI_org_1jni_11zero_1SampleForT
jlong nativeCPPClass,
jobject caller,
jbyteArray bytes) {
std::vector<uint8_t> bytes_converted = jni_zero::ConvertArray<std::vector<uint8_t>>::FromJniType(
std::vector<uint8_t> bytes_converted = jni_zero::FromJniArray<std::vector<uint8_t>>(
env,
jni_zero::JavaParamRef<jbyteArray>(env, static_cast<jbyteArray>(bytes)));
reinterpret_cast<CPPClass*>(nativeCPPClass)->Destroy(
@ -177,13 +170,13 @@ JNI_BOUNDARY_EXPORT jlong Java_org_jni_1zero_GEN_1JNI_org_1jni_11zero_1SampleFor
jbyteArray bytes,
jobject convertedType,
jobjectArray nonConvertedArray) {
jni_zero::ByteArrayView bytes_converted = jni_zero::ConvertArray<jni_zero::ByteArrayView>::FromJniType(
jni_zero::ByteArrayView bytes_converted = jni_zero::FromJniArray<jni_zero::ByteArrayView>(
env,
jni_zero::JavaParamRef<jbyteArray>(env, static_cast<jbyteArray>(bytes)));
jni_zero::tests::CPPClass* convertedType_converted = jni_zero::FromJniType<jni_zero::tests::CPPClass*>(
env,
jni_zero::JavaParamRef<jobject>(env, convertedType));
std::vector<jni_zero::ScopedJavaLocalRef<jobject>> nonConvertedArray_converted = jni_zero::ConvertArray<std::vector<jni_zero::ScopedJavaLocalRef<jobject>>>::FromJniType(
std::vector<jni_zero::ScopedJavaLocalRef<jobject>> nonConvertedArray_converted = jni_zero::FromJniArray<std::vector<jni_zero::ScopedJavaLocalRef<jobject>>>(
env,
jni_zero::JavaParamRef<jobjectArray>(env, static_cast<jobjectArray>(nonConvertedArray)));
auto _ret = JNI_SampleForTests_Init(
@ -212,7 +205,7 @@ JNI_BOUNDARY_EXPORT jint Java_org_jni_1zero_GEN_1JNI_org_1jni_11zero_1SampleForT
jlong nativeCPPClass,
jobject caller,
jobjectArray strings) {
std::vector<std::string> strings_converted = jni_zero::ConvertArray<std::vector<std::string>>::FromJniType(
std::vector<std::string> strings_converted = jni_zero::FromJniArray<std::vector<std::string>>(
env,
jni_zero::JavaParamRef<jobjectArray>(env, static_cast<jobjectArray>(strings)));
auto _ret = reinterpret_cast<CPPClass*>(nativeCPPClass)->Method(
@ -338,11 +331,11 @@ static std::string Java_SampleForTests_getFirstString(
"getFirstString",
"([Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
&cached_method_id);
jni_zero::ScopedJavaLocalRef<jobject> converted_array = jni_zero::ConvertArray<std::vector<const char*>>::ToJniType(
jni_zero::ScopedJavaLocalRef<jobject> converted_array = jni_zero::ToJniArray(
env,
array,
jni_zero::g_string_class);
jni_zero::ScopedJavaLocalRef<jobject> converted_finalArg = jni_zero::ToJniType<const char*>(
jni_zero::ScopedJavaLocalRef<jobject> converted_finalArg = jni_zero::ToJniType(
env,
finalArg);
auto _ret = env->CallObjectMethod(
@ -486,7 +479,7 @@ static std::vector<int32_t> Java_SampleForTests_jniTypesAndAnnotations(
"(I[IIJ)[I",
&cached_method_id);
jint converted_foo = static_cast<jint>(foo);
jni_zero::ScopedJavaLocalRef<jobject> converted_bar = jni_zero::ConvertArray<std::vector<int32_t>>::ToJniType(
jni_zero::ScopedJavaLocalRef<jobject> converted_bar = jni_zero::ToJniArray(
env,
bar);
jlong converted_bat = static_cast<jlong>(bat);
@ -497,7 +490,7 @@ static std::vector<int32_t> Java_SampleForTests_jniTypesAndAnnotations(
converted_bar.obj(),
as_jint(baz),
converted_bat);
return jni_zero::ConvertArray<std::vector<int32_t>>::FromJniType(
return jni_zero::FromJniArray<std::vector<int32_t>>(
env,
jni_zero::ScopedJavaLocalRef<jintArray>(env, static_cast<jintArray>(_ret)));
}

@ -20,14 +20,6 @@ inline jclass org_jni_1zero_SampleForAnnotationProcessor_clazz(JNIEnv* env) {
}
#endif
// Forward declare used conversion functions to avoid a compiler warning that
// triggers if a conversion specialization exists within the including .cc file.
namespace jni_zero {
template<> jni_zero::ScopedJavaLocalRef<jobject> ToJniType<std::string>(JNIEnv*, std::string const&);
template<> jni_zero::tests::CPPClass FromJniType<jni_zero::tests::CPPClass>(JNIEnv*, const JavaRef<jobject>&);
template<> std::optional<std::string> FromJniType<std::optional<std::string>>(JNIEnv*, const JavaRef<jobject>&);
template<> std::string FromJniType<std::string>(JNIEnv*, const JavaRef<jobject>&);
} // namespace jni_zero
// Java to native functions
// Forward declaration. To be implemented by the including .cc file.
static jni_zero::ScopedJavaLocalRef<jobject> JNI_SampleForAnnotationProcessor_Bar(
@ -94,10 +86,7 @@ JNI_BOUNDARY_EXPORT jobjectArray Java_org_jni_1zero_GEN_1JNI_org_1jni_11zero_1Sa
jclass jcaller,
jclass __arrayClazz) {
auto _ret = JNI_SampleForAnnotationProcessor_ReturnConvertedAppObjects(env);
jobject converted_ret = jni_zero::ConvertArray<std::vector<jni_zero::ScopedJavaLocalRef<jobject>>>::ToJniType(
env,
_ret,
__arrayClazz).Release();
jobject converted_ret = jni_zero::ToJniArray(env, _ret, __arrayClazz).Release();
return static_cast<jobjectArray>(converted_ret);
}
@ -109,9 +98,7 @@ JNI_BOUNDARY_EXPORT jintArray Java_org_jni_1zero_GEN_1JNI_org_1jni_11zero_1Sampl
JNIEnv* env,
jclass jcaller) {
auto _ret = JNI_SampleForAnnotationProcessor_ReturnConvertedInts(env);
jobject converted_ret = jni_zero::ConvertArray<std::vector<jint>>::ToJniType(
env,
_ret).Release();
jobject converted_ret = jni_zero::ToJniArray(env, _ret).Release();
return static_cast<jintArray>(converted_ret);
}
@ -123,7 +110,7 @@ JNI_BOUNDARY_EXPORT jstring Java_org_jni_1zero_GEN_1JNI_org_1jni_11zero_1SampleF
JNIEnv* env,
jclass jcaller) {
auto _ret = JNI_SampleForAnnotationProcessor_ReturnConvertedString(env);
jobject converted_ret = jni_zero::ToJniType<std::string>(env, _ret).Release();
jobject converted_ret = jni_zero::ToJniType(env, _ret).Release();
return static_cast<jstring>(converted_ret);
}
@ -135,7 +122,7 @@ JNI_BOUNDARY_EXPORT jobjectArray Java_org_jni_1zero_GEN_1JNI_org_1jni_11zero_1Sa
JNIEnv* env,
jclass jcaller) {
auto _ret = JNI_SampleForAnnotationProcessor_ReturnConvertedStrings(env);
jobject converted_ret = jni_zero::ConvertArray<std::vector<std::string>>::ToJniType(
jobject converted_ret = jni_zero::ToJniArray(
env,
_ret,
jni_zero::g_string_class).Release();
@ -315,7 +302,7 @@ JNI_BOUNDARY_EXPORT jintArray Java_org_jni_1zero_GEN_1JNI_org_1jni_11zero_1Sampl
jboolean zbool,
jbooleanArray bools) {
int zint_converted = static_cast<int>(zint);
std::vector<int32_t> ints_converted = jni_zero::ConvertArray<std::vector<int32_t>>::FromJniType(
std::vector<int32_t> ints_converted = jni_zero::FromJniArray<std::vector<int32_t>>(
env,
jni_zero::JavaParamRef<jintArray>(env, static_cast<jintArray>(ints)));
int zchar_converted = static_cast<int>(zchar);
@ -337,9 +324,7 @@ JNI_BOUNDARY_EXPORT jintArray Java_org_jni_1zero_GEN_1JNI_org_1jni_11zero_1Sampl
jni_zero::JavaParamRef<jfloatArray>(env, floats),
zbool,
jni_zero::JavaParamRef<jbooleanArray>(env, bools));
jobject converted_ret = jni_zero::ConvertArray<std::vector<int32_t>>::ToJniType(
env,
_ret).Release();
jobject converted_ret = jni_zero::ToJniArray(env, _ret).Release();
return static_cast<jintArray>(converted_ret);
}
@ -389,7 +374,7 @@ JNI_BOUNDARY_EXPORT void Java_org_jni_1zero_GEN_1JNI_org_1jni_11zero_1SampleForA
std::string convertedString_converted = jni_zero::FromJniType<std::string>(
env,
jni_zero::JavaParamRef<jobject>(env, convertedString));
std::vector<std::string> convertedStrings_converted = jni_zero::ConvertArray<std::vector<std::string>>::FromJniType(
std::vector<std::string> convertedStrings_converted = jni_zero::FromJniArray<std::vector<std::string>>(
env,
jni_zero::JavaParamRef<jobjectArray>(env, static_cast<jobjectArray>(convertedStrings)));
std::optional<std::string> optionalString_converted = jni_zero::FromJniType<std::optional<std::string>>(
@ -398,7 +383,7 @@ JNI_BOUNDARY_EXPORT void Java_org_jni_1zero_GEN_1JNI_org_1jni_11zero_1SampleForA
jni_zero::tests::CPPClass convertedObj_converted = jni_zero::FromJniType<jni_zero::tests::CPPClass>(
env,
jni_zero::JavaParamRef<jobject>(env, convertedObj));
std::vector<jni_zero::tests::CPPClass> convertedObjects_converted = jni_zero::ConvertArray<std::vector<jni_zero::tests::CPPClass>>::FromJniType(
std::vector<jni_zero::tests::CPPClass> convertedObjects_converted = jni_zero::FromJniArray<std::vector<jni_zero::tests::CPPClass>>(
env,
jni_zero::JavaParamRef<jobjectArray>(env, static_cast<jobjectArray>(convertedObjects)));
JNI_SampleForAnnotationProcessor_TestSpecialTypes(

@ -38,13 +38,6 @@ inline jclass this_is_a_package_prefix_org_jni_1zero_SampleForTests_00024InnerSt
}
#endif
// Forward declare used conversion functions to avoid a compiler warning that
// triggers if a conversion specialization exists within the including .cc file.
namespace jni_zero {
template<> jni_zero::ScopedJavaLocalRef<jobject> ToJniType<const char*>(JNIEnv*, const char* const&);
template<> jni_zero::tests::CPPClass* FromJniType<jni_zero::tests::CPPClass*>(JNIEnv*, const JavaRef<jobject>&);
template<> std::string FromJniType<std::string>(JNIEnv*, const JavaRef<jobject>&);
} // namespace jni_zero
namespace jni_zero {
namespace tests {
// Java to native functions
@ -66,7 +59,7 @@ JNI_BOUNDARY_EXPORT void Java_this_is_a_package_prefix_org_jni_1zero_GEN_1JNI_th
jlong nativeCPPClass,
jobject caller,
jbyteArray bytes) {
std::vector<uint8_t> bytes_converted = jni_zero::ConvertArray<std::vector<uint8_t>>::FromJniType(
std::vector<uint8_t> bytes_converted = jni_zero::FromJniArray<std::vector<uint8_t>>(
env,
jni_zero::JavaParamRef<jbyteArray>(env, static_cast<jbyteArray>(bytes)));
reinterpret_cast<CPPClass*>(nativeCPPClass)->Destroy(
@ -177,13 +170,13 @@ JNI_BOUNDARY_EXPORT jlong Java_this_is_a_package_prefix_org_jni_1zero_GEN_1JNI_t
jbyteArray bytes,
jobject convertedType,
jobjectArray nonConvertedArray) {
jni_zero::ByteArrayView bytes_converted = jni_zero::ConvertArray<jni_zero::ByteArrayView>::FromJniType(
jni_zero::ByteArrayView bytes_converted = jni_zero::FromJniArray<jni_zero::ByteArrayView>(
env,
jni_zero::JavaParamRef<jbyteArray>(env, static_cast<jbyteArray>(bytes)));
jni_zero::tests::CPPClass* convertedType_converted = jni_zero::FromJniType<jni_zero::tests::CPPClass*>(
env,
jni_zero::JavaParamRef<jobject>(env, convertedType));
std::vector<jni_zero::ScopedJavaLocalRef<jobject>> nonConvertedArray_converted = jni_zero::ConvertArray<std::vector<jni_zero::ScopedJavaLocalRef<jobject>>>::FromJniType(
std::vector<jni_zero::ScopedJavaLocalRef<jobject>> nonConvertedArray_converted = jni_zero::FromJniArray<std::vector<jni_zero::ScopedJavaLocalRef<jobject>>>(
env,
jni_zero::JavaParamRef<jobjectArray>(env, static_cast<jobjectArray>(nonConvertedArray)));
auto _ret = JNI_SampleForTests_Init(
@ -212,7 +205,7 @@ JNI_BOUNDARY_EXPORT jint Java_this_is_a_package_prefix_org_jni_1zero_GEN_1JNI_th
jlong nativeCPPClass,
jobject caller,
jobjectArray strings) {
std::vector<std::string> strings_converted = jni_zero::ConvertArray<std::vector<std::string>>::FromJniType(
std::vector<std::string> strings_converted = jni_zero::FromJniArray<std::vector<std::string>>(
env,
jni_zero::JavaParamRef<jobjectArray>(env, static_cast<jobjectArray>(strings)));
auto _ret = reinterpret_cast<CPPClass*>(nativeCPPClass)->Method(
@ -338,11 +331,11 @@ static std::string Java_SampleForTests_getFirstString(
"getFirstString",
"([Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
&cached_method_id);
jni_zero::ScopedJavaLocalRef<jobject> converted_array = jni_zero::ConvertArray<std::vector<const char*>>::ToJniType(
jni_zero::ScopedJavaLocalRef<jobject> converted_array = jni_zero::ToJniArray(
env,
array,
jni_zero::g_string_class);
jni_zero::ScopedJavaLocalRef<jobject> converted_finalArg = jni_zero::ToJniType<const char*>(
jni_zero::ScopedJavaLocalRef<jobject> converted_finalArg = jni_zero::ToJniType(
env,
finalArg);
auto _ret = env->CallObjectMethod(
@ -486,7 +479,7 @@ static std::vector<int32_t> Java_SampleForTests_jniTypesAndAnnotations(
"(I[IIJ)[I",
&cached_method_id);
jint converted_foo = static_cast<jint>(foo);
jni_zero::ScopedJavaLocalRef<jobject> converted_bar = jni_zero::ConvertArray<std::vector<int32_t>>::ToJniType(
jni_zero::ScopedJavaLocalRef<jobject> converted_bar = jni_zero::ToJniArray(
env,
bar);
jlong converted_bat = static_cast<jlong>(bat);
@ -497,7 +490,7 @@ static std::vector<int32_t> Java_SampleForTests_jniTypesAndAnnotations(
converted_bar.obj(),
as_jint(baz),
converted_bat);
return jni_zero::ConvertArray<std::vector<int32_t>>::FromJniType(
return jni_zero::FromJniArray<std::vector<int32_t>>(
env,
jni_zero::ScopedJavaLocalRef<jintArray>(env, static_cast<jintArray>(_ret)));
}

@ -20,14 +20,6 @@ inline jclass org_jni_1zero_SampleForAnnotationProcessor_clazz(JNIEnv* env) {
}
#endif
// Forward declare used conversion functions to avoid a compiler warning that
// triggers if a conversion specialization exists within the including .cc file.
namespace jni_zero {
template<> jni_zero::ScopedJavaLocalRef<jobject> ToJniType<std::string>(JNIEnv*, std::string const&);
template<> jni_zero::tests::CPPClass FromJniType<jni_zero::tests::CPPClass>(JNIEnv*, const JavaRef<jobject>&);
template<> std::optional<std::string> FromJniType<std::optional<std::string>>(JNIEnv*, const JavaRef<jobject>&);
template<> std::string FromJniType<std::string>(JNIEnv*, const JavaRef<jobject>&);
} // namespace jni_zero
// Java to native functions
// Forward declaration. To be implemented by the including .cc file.
static jni_zero::ScopedJavaLocalRef<jobject> JNI_SampleForAnnotationProcessor_Bar(
@ -94,10 +86,7 @@ JNI_BOUNDARY_EXPORT jobjectArray Java_org_jni_1zero_SampleForAnnotationProcessor
jclass jcaller,
jclass __arrayClazz) {
auto _ret = JNI_SampleForAnnotationProcessor_ReturnConvertedAppObjects(env);
jobject converted_ret = jni_zero::ConvertArray<std::vector<jni_zero::ScopedJavaLocalRef<jobject>>>::ToJniType(
env,
_ret,
__arrayClazz).Release();
jobject converted_ret = jni_zero::ToJniArray(env, _ret, __arrayClazz).Release();
return static_cast<jobjectArray>(converted_ret);
}
@ -109,9 +98,7 @@ JNI_BOUNDARY_EXPORT jintArray Java_org_jni_1zero_SampleForAnnotationProcessorJni
JNIEnv* env,
jclass jcaller) {
auto _ret = JNI_SampleForAnnotationProcessor_ReturnConvertedInts(env);
jobject converted_ret = jni_zero::ConvertArray<std::vector<jint>>::ToJniType(
env,
_ret).Release();
jobject converted_ret = jni_zero::ToJniArray(env, _ret).Release();
return static_cast<jintArray>(converted_ret);
}
@ -123,7 +110,7 @@ JNI_BOUNDARY_EXPORT jstring Java_org_jni_1zero_SampleForAnnotationProcessorJni_n
JNIEnv* env,
jclass jcaller) {
auto _ret = JNI_SampleForAnnotationProcessor_ReturnConvertedString(env);
jobject converted_ret = jni_zero::ToJniType<std::string>(env, _ret).Release();
jobject converted_ret = jni_zero::ToJniType(env, _ret).Release();
return static_cast<jstring>(converted_ret);
}
@ -135,7 +122,7 @@ JNI_BOUNDARY_EXPORT jobjectArray Java_org_jni_1zero_SampleForAnnotationProcessor
JNIEnv* env,
jclass jcaller) {
auto _ret = JNI_SampleForAnnotationProcessor_ReturnConvertedStrings(env);
jobject converted_ret = jni_zero::ConvertArray<std::vector<std::string>>::ToJniType(
jobject converted_ret = jni_zero::ToJniArray(
env,
_ret,
jni_zero::g_string_class).Release();
@ -315,7 +302,7 @@ JNI_BOUNDARY_EXPORT jintArray Java_org_jni_1zero_SampleForAnnotationProcessorJni
jboolean zbool,
jbooleanArray bools) {
int zint_converted = static_cast<int>(zint);
std::vector<int32_t> ints_converted = jni_zero::ConvertArray<std::vector<int32_t>>::FromJniType(
std::vector<int32_t> ints_converted = jni_zero::FromJniArray<std::vector<int32_t>>(
env,
jni_zero::JavaParamRef<jintArray>(env, static_cast<jintArray>(ints)));
int zchar_converted = static_cast<int>(zchar);
@ -337,9 +324,7 @@ JNI_BOUNDARY_EXPORT jintArray Java_org_jni_1zero_SampleForAnnotationProcessorJni
jni_zero::JavaParamRef<jfloatArray>(env, floats),
zbool,
jni_zero::JavaParamRef<jbooleanArray>(env, bools));
jobject converted_ret = jni_zero::ConvertArray<std::vector<int32_t>>::ToJniType(
env,
_ret).Release();
jobject converted_ret = jni_zero::ToJniArray(env, _ret).Release();
return static_cast<jintArray>(converted_ret);
}
@ -389,7 +374,7 @@ JNI_BOUNDARY_EXPORT void Java_org_jni_1zero_SampleForAnnotationProcessorJni_nati
std::string convertedString_converted = jni_zero::FromJniType<std::string>(
env,
jni_zero::JavaParamRef<jobject>(env, convertedString));
std::vector<std::string> convertedStrings_converted = jni_zero::ConvertArray<std::vector<std::string>>::FromJniType(
std::vector<std::string> convertedStrings_converted = jni_zero::FromJniArray<std::vector<std::string>>(
env,
jni_zero::JavaParamRef<jobjectArray>(env, static_cast<jobjectArray>(convertedStrings)));
std::optional<std::string> optionalString_converted = jni_zero::FromJniType<std::optional<std::string>>(
@ -398,7 +383,7 @@ JNI_BOUNDARY_EXPORT void Java_org_jni_1zero_SampleForAnnotationProcessorJni_nati
jni_zero::tests::CPPClass convertedObj_converted = jni_zero::FromJniType<jni_zero::tests::CPPClass>(
env,
jni_zero::JavaParamRef<jobject>(env, convertedObj));
std::vector<jni_zero::tests::CPPClass> convertedObjects_converted = jni_zero::ConvertArray<std::vector<jni_zero::tests::CPPClass>>::FromJniType(
std::vector<jni_zero::tests::CPPClass> convertedObjects_converted = jni_zero::FromJniArray<std::vector<jni_zero::tests::CPPClass>>(
env,
jni_zero::JavaParamRef<jobjectArray>(env, static_cast<jobjectArray>(convertedObjects)));
JNI_SampleForAnnotationProcessor_TestSpecialTypes(

@ -20,11 +20,6 @@ inline jclass org_jni_1zero_SampleUniqueAnnotations_clazz(JNIEnv* env) {
}
#endif
// Forward declare used conversion functions to avoid a compiler warning that
// triggers if a conversion specialization exists within the including .cc file.
namespace jni_zero {
template<> std::string FromJniType<std::string>(JNIEnv*, const JavaRef<jobject>&);
} // namespace jni_zero
// Java to native functions
// Forward declaration. To be implemented by the including .cc file.
static jint JNI_SampleUniqueAnnotations_Bar(JNIEnv* env, jint x, jint y);

@ -2,9 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/jni_zero/test/sample_for_tests.h"
#include <iostream>
#include "third_party/jni_zero/test/sample_for_tests.h"
#include "third_party/jni_zero/test/stub_conversions.h"
// Generated file for JNI bindings from C++ to Java @CalledByNative methods.
// Only to be included in one .cc file.
@ -28,69 +30,7 @@ using jni_zero::AttachCurrentThread;
using jni_zero::JavaParamRef;
using jni_zero::ScopedJavaLocalRef;
namespace jni_zero {
// "conversion" functions, this file only has to compile not run.
template <>
tests::CPPClass FromJniType<tests::CPPClass>(JNIEnv* env,
const JavaRef<jobject>& j_obj) {
return {};
}
template <>
std::string FromJniType<std::string>(JNIEnv* env,
const JavaRef<jobject>& input) {
return {};
}
template <>
ScopedJavaLocalRef<jobject> ToJniType<std::string>(JNIEnv* env,
const std::string& input) {
return {};
}
template <>
std::u16string FromJniType<std::u16string>(JNIEnv* env,
const JavaRef<jobject>& input) {
return {};
}
template <>
ScopedJavaLocalRef<jobject> ToJniType<std::u16string>(
JNIEnv* env,
const std::u16string& input) {
return {};
}
template <>
ScopedJavaLocalRef<jobject> ToJniType<const char*>(JNIEnv* env,
const char* const& input) {
return {};
}
template <>
tests::CPPClass* FromJniType<tests::CPPClass*>(JNIEnv* env, const JavaRef<jobject>& j_obj) {
return nullptr;
}
// Specialized conversions for std::optional<std::basic_string<T>> since jstring
// is a nullable type but std::basic_string<T> is not.
template <>
std::optional<std::string> FromJniType<std::optional<std::string>>(
JNIEnv* env,
const JavaRef<jobject>& j_string) {
if (!j_string) {
return std::nullopt;
}
return std::optional<std::string>(FromJniType<std::string>(env, j_string));
}
template <>
std::optional<std::u16string> FromJniType<std::optional<std::u16string>>(
JNIEnv* env,
const JavaRef<jobject>& j_string) {
if (!j_string) {
return std::nullopt;
}
return std::optional<std::u16string>(
FromJniType<std::u16string>(env, j_string));
}
namespace tests {
namespace jni_zero::tests {
jdouble CPPClass::InnerClass::MethodOtherP0(
JNIEnv* env,
@ -205,8 +145,7 @@ static ScopedJavaLocalRef<jobject> JNI_SampleForTests_GetMap(
return ScopedJavaLocalRef<jobject>();
}
} // namespace tests
} // namespace jni_zero
} // namespace jni_zero::tests
// Proxy natives.
static void JNI_SampleForAnnotationProcessor_Foo(JNIEnv* env) {}

@ -0,0 +1,50 @@
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef _JNI_ZERO_STUB_CONVERSIONS_H_
#define _JNI_ZERO_STUB_CONVERSIONS_H_
#include "third_party/jni_zero/jni_zero.h"
namespace jni_zero {
// "conversion" functions, this file only has to compile not run.
template <>
tests::CPPClass FromJniType<tests::CPPClass>(JNIEnv* env,
const JavaRef<jobject>& j_obj) {
return {};
}
template <>
std::string FromJniType<std::string>(JNIEnv* env,
const JavaRef<jobject>& input) {
return {};
}
template <>
ScopedJavaLocalRef<jobject> ToJniType<std::string>(JNIEnv* env,
const std::string& input) {
return {};
}
template <>
std::u16string FromJniType<std::u16string>(JNIEnv* env,
const JavaRef<jobject>& input) {
return {};
}
template <>
ScopedJavaLocalRef<jobject> ToJniType<std::u16string>(
JNIEnv* env,
const std::u16string& input) {
return {};
}
template <>
ScopedJavaLocalRef<jobject> ToJniType<const char>(JNIEnv* env, const char* input) {
return {};
}
template <>
tests::CPPClass* FromJniType<tests::CPPClass*>(JNIEnv* env,
const JavaRef<jobject>& j_obj) {
return nullptr;
}
} // namespace jni_zero
#endif

@ -26,17 +26,15 @@ namespace jni_zero {
// Note: |j_bitmap| is assumed to be non-null, non-empty and of format
// RGBA_8888.
template <>
GFX_EXPORT SkBitmap FromJniType<SkBitmap>(JNIEnv* env,
const JavaRef<jobject>& j_bitmap) {
SkBitmap FromJniType<SkBitmap>(JNIEnv* env, const JavaRef<jobject>& j_bitmap) {
return gfx::CreateSkBitmapFromJavaBitmap(gfx::JavaBitmap(j_bitmap));
}
// Converts |skbitmap| to a Java-backed bitmap (android.graphics.Bitmap).
// Note: return nullptr jobject if |skbitmap| is null or empty.
template <>
GFX_EXPORT ScopedJavaLocalRef<jobject> ToJniType<SkBitmap>(
JNIEnv* env,
const SkBitmap& skbitmap) {
ScopedJavaLocalRef<jobject> ToJniType<SkBitmap>(JNIEnv* env,
const SkBitmap& skbitmap) {
if (skbitmap.drawsNothing()) {
return {};
}

@ -80,4 +80,20 @@ ConvertToSkiaColorType(const base::android::JavaRef<jobject>& jbitmap_config);
} // namespace gfx
namespace jni_zero {
// Converts |bitmap| to an SkBitmap of the same size and format.
// Note: |j_bitmap| is assumed to be non-null, non-empty and of format
// RGBA_8888.
template <>
GFX_EXPORT SkBitmap FromJniType<SkBitmap>(JNIEnv* env,
const JavaRef<jobject>& j_bitmap);
// Converts |skbitmap| to a Java-backed bitmap (android.graphics.Bitmap).
// Note: return nullptr jobject if |skbitmap| is null or empty.
template <>
GFX_EXPORT ScopedJavaLocalRef<jobject> ToJniType<SkBitmap>(
JNIEnv* env,
const SkBitmap& skbitmap);
} // namespace jni_zero
#endif // UI_GFX_ANDROID_JAVA_BITMAP_H_

@ -8,7 +8,6 @@
#include <string>
#include <vector>
#include "base/android/jni_android.h"
#include "base/android/jni_string.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
@ -16,6 +15,8 @@
#include "base/strings/string_util.h"
#include "url/android/parsed_android.h"
#include "url/third_party/mozilla/url_parse.h"
//
// Must come after all headers that specialize FromJniType() / ToJniType().
#include "url/url_jni_headers/GURL_jni.h"
using jni_zero::AttachCurrentThread;
@ -23,36 +24,8 @@ using jni_zero::JavaParamRef;
using jni_zero::JavaRef;
using jni_zero::ScopedJavaLocalRef;
namespace jni_zero {
// Convert from java GURL.java pointer to native GURL object.
template <>
COMPONENT_EXPORT(URL)
GURL FromJniType<GURL>(JNIEnv* env, const JavaRef<jobject>& j_gurl) {
return url::GURLAndroid::ToNativeGURL(env, j_gurl);
}
// Convert from native GURL object to a GURL.java object pointer.
template <>
COMPONENT_EXPORT(URL)
ScopedJavaLocalRef<jobject> ToJniType<GURL>(JNIEnv* env, const GURL& gurl) {
return url::GURLAndroid::FromNativeGURL(env, gurl);
}
// Enables vector<const GURL*> to avoid copies.
template <>
COMPONENT_EXPORT(URL)
ScopedJavaLocalRef<jobject> ToJniType<const GURL*>(JNIEnv* env,
const GURL* const& gurl) {
if (!gurl) {
return nullptr;
}
return url::GURLAndroid::FromNativeGURL(env, *gurl);
}
} // namespace jni_zero
namespace url {
namespace {
static void InitFromGURL(JNIEnv* env,

@ -23,4 +23,20 @@ class COMPONENT_EXPORT(URL) GURLAndroid {
} // namespace url
namespace jni_zero {
// Convert from java GURL.java pointer to native GURL object.
template <>
inline GURL FromJniType<GURL>(JNIEnv* env, const JavaRef<jobject>& j_gurl) {
return url::GURLAndroid::ToNativeGURL(env, j_gurl);
}
// Convert from native GURL object to a GURL.java object pointer.
template <>
inline ScopedJavaLocalRef<jobject> ToJniType<GURL>(JNIEnv* env,
const GURL& gurl) {
return url::GURLAndroid::FromNativeGURL(env, gurl);
}
} // namespace jni_zero
#endif // URL_ANDROID_GURL_ANDROID_H_

@ -6,11 +6,12 @@
#include <cstdint>
#include "base/android/jni_android.h"
#include "base/android/jni_string.h"
#include "base/android/scoped_java_ref.h"
#include "base/memory/ptr_util.h"
#include "url/android/gurl_android.h"
// Must come after all headers that specialize FromJniType() / ToJniType().
#include "url/url_jni_headers/Origin_jni.h"
namespace url {