diff options
author | joth@chromium.org <joth@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-09-09 10:17:35 +0000 |
---|---|---|
committer | joth@chromium.org <joth@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-09-09 10:17:35 +0000 |
commit | f98d7b97c373ad9d65cc102f19acdc43ec3da604 (patch) | |
tree | ca11bd5920735238b4fd4b6e62585e81ec39b020 /base/android | |
parent | f2b7e994d1f0b4c12d91e7e93f6e617c318f062e (diff) | |
download | chromium_src-f98d7b97c373ad9d65cc102f19acdc43ec3da604.zip chromium_src-f98d7b97c373ad9d65cc102f19acdc43ec3da604.tar.gz chromium_src-f98d7b97c373ad9d65cc102f19acdc43ec3da604.tar.bz2 |
Refactor ScopedJavaRef
- introduces JavaRef<> base class to allow passing refs without knowledge of their scope
- makes the ScopedJavaLocalRef and ScopedJavaGlobalRef consistent, in name, in methods available, and in conversions allowed.
Also updates some other minor base API changes whilst I'm in those files.
BUG=
TEST=doesn't break build...
Review URL: http://codereview.chromium.org/7828084
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@100383 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/android')
-rw-r--r-- | base/android/jni_android.cc | 10 | ||||
-rw-r--r-- | base/android/jni_android.h | 7 | ||||
-rw-r--r-- | base/android/jni_array.cc | 44 | ||||
-rw-r--r-- | base/android/jni_array.h | 3 | ||||
-rw-r--r-- | base/android/jni_string.cc | 13 | ||||
-rw-r--r-- | base/android/jni_string.h | 3 | ||||
-rw-r--r-- | base/android/path_utils.cc | 6 | ||||
-rw-r--r-- | base/android/scoped_java_global_reference.h | 63 | ||||
-rw-r--r-- | base/android/scoped_java_ref.cc | 47 | ||||
-rw-r--r-- | base/android/scoped_java_ref.h | 175 | ||||
-rw-r--r-- | base/android/scoped_java_ref_unittest.cc | 114 | ||||
-rw-r--r-- | base/android/scoped_java_reference.h | 69 |
12 files changed, 396 insertions, 158 deletions
diff --git a/base/android/jni_android.cc b/base/android/jni_android.cc index 9c655ac..1dc02af 100644 --- a/base/android/jni_android.cc +++ b/base/android/jni_android.cc @@ -56,6 +56,16 @@ jmethodID GetMethodID(JNIEnv* env, return id; } +jmethodID GetStaticMethodID(JNIEnv* env, + jclass clazz, + const char* const method, + const char* const jni_signature) { + jmethodID id = env->GetStaticMethodID(clazz, method, jni_signature); + DCHECK(id) << method; + CheckException(env); + return id; +} + bool CheckException(JNIEnv* env) { if (env->ExceptionCheck() == JNI_FALSE) return false; diff --git a/base/android/jni_android.h b/base/android/jni_android.h index 9a15895..66b3134 100644 --- a/base/android/jni_android.h +++ b/base/android/jni_android.h @@ -37,6 +37,13 @@ jmethodID GetMethodID(JNIEnv* env, const char* const method, const char* const jni_signature); +// Get the method ID for a class static method. Will clear the pending Java +// exception and return 0 if the method is not found. +jmethodID GetStaticMethodID(JNIEnv* env, + jclass clazz, + const char* const method, + const char* const jni_signature); + // Returns true if an exception is pending in the provided JNIEnv*. // If an exception is pending, it is printed. bool CheckException(JNIEnv* env); diff --git a/base/android/jni_array.cc b/base/android/jni_array.cc index 409b44a..08cb42e 100644 --- a/base/android/jni_array.cc +++ b/base/android/jni_array.cc @@ -5,7 +5,8 @@ #include "base/android/jni_array.h" #include "base/android/jni_android.h" -#include "base/android/scoped_java_reference.h" +#include "base/android/jni_string.h" +#include "base/android/scoped_java_ref.h" #include "base/logging.h" namespace base { @@ -15,12 +16,10 @@ jbyteArray ToJavaByteArray(JNIEnv* env, const unsigned char* bytes, size_t len) { jbyteArray byte_array = env->NewByteArray(len); - if (!byte_array) { - return NULL; - } + CheckException(env); + CHECK(byte_array); jbyte* elements = env->GetByteArrayElements(byte_array, NULL); - DCHECK(elements); memcpy(elements, bytes, len); env->ReleaseByteArrayElements(byte_array, elements, 0); CheckException(env); @@ -30,24 +29,33 @@ jbyteArray ToJavaByteArray(JNIEnv* env, jobjectArray ToJavaArrayOfByteArray(JNIEnv* env, const std::vector<std::string>& v) { - size_t count = v.size(); - DCHECK_GT(count, 0U); - jclass byte_array_class = env->FindClass("[B"); - jobjectArray joa = env->NewObjectArray(count, byte_array_class, NULL); - if (joa == NULL) - return NULL; - - for (size_t i = 0; i < count; ++i) { - ScopedJavaReference<jobject> byte_array(env, ToJavaByteArray(env, + ScopedJavaLocalRef<jclass> byte_array_clazz(env, env->FindClass("[B")); + jobjectArray joa = env->NewObjectArray(v.size(), + byte_array_clazz.obj(), NULL); + CheckException(env); + + for (size_t i = 0; i < v.size(); ++i) { + ScopedJavaLocalRef<jobject> byte_array(env, ToJavaByteArray(env, reinterpret_cast<const uint8*>(v[i].data()), v[i].length())); - if (!byte_array.obj()) { - env->DeleteLocalRef(joa); - return NULL; - } env->SetObjectArrayElement(joa, i, byte_array.obj()); } return joa; } +jobjectArray ToJavaArrayOfStrings(JNIEnv* env, + const std::vector<std::string>& v) { + ScopedJavaLocalRef<jclass> string_clazz(env, + env->FindClass("java/lang/String")); + jobjectArray joa = env->NewObjectArray(v.size(), string_clazz.obj(), NULL); + CheckException(env); + + for (size_t i = 0; i < v.size(); ++i) { + ScopedJavaLocalRef<jstring> item(env, + ConvertUTF8ToJavaString(env, v[i])); + env->SetObjectArrayElement(joa, i, item.obj()); + } + return joa; +} + } // namespace android } // namespace base diff --git a/base/android/jni_array.h b/base/android/jni_array.h index e3b0194..edf05c6 100644 --- a/base/android/jni_array.h +++ b/base/android/jni_array.h @@ -19,6 +19,9 @@ jbyteArray ToJavaByteArray(JNIEnv* env, const unsigned char* bytes, size_t len); jobjectArray ToJavaArrayOfByteArray(JNIEnv* env, const std::vector<std::string>& v); +jobjectArray ToJavaArrayOfStrings(JNIEnv* env, + const std::vector<std::string>& v); + } // namespace android } // namespace base diff --git a/base/android/jni_string.cc b/base/android/jni_string.cc index 3f3ba82..26e7114 100644 --- a/base/android/jni_string.cc +++ b/base/android/jni_string.cc @@ -17,10 +17,15 @@ std::string ConvertJavaStringToUTF8(JNIEnv* env, jstring str) { return UTF16ToUTF8(ConvertJavaStringToUTF16(env, str)); } -jstring ConvertUTF8ToJavaString(JNIEnv* env, const std::string& str) { - jstring result = env->NewStringUTF(str.c_str()); - CheckException(env); - return result; +jstring ConvertUTF8ToJavaString(JNIEnv* env, const base::StringPiece& str) { + // JNI's NewStringUTF expects "modified" UTF8 so instead create the string + // via our own UTF16 conversion utility. + // Further, Dalvik requires the string passed into NewStringUTF() to come from + // a trusted source. We can't guarantee that all UTF8 will be sanitized before + // it gets here, so constructing via UTF16 side-steps this issue. + // (Dalvik stores strings internally as UTF16 anyway, so there shouldn't be + // a significant performance hit by doing it this way). + return ConvertUTF16ToJavaString(env, UTF8ToUTF16(str)); } string16 ConvertJavaStringToUTF16(JNIEnv* env, jstring str) { diff --git a/base/android/jni_string.h b/base/android/jni_string.h index 7e45154..bb902d1 100644 --- a/base/android/jni_string.h +++ b/base/android/jni_string.h @@ -9,6 +9,7 @@ #include <string> #include "base/string16.h" +#include "base/string_piece.h" namespace base { namespace android { @@ -17,7 +18,7 @@ namespace android { std::string ConvertJavaStringToUTF8(JNIEnv* env, jstring str); // Convert a std string to Java string. -jstring ConvertUTF8ToJavaString(JNIEnv* env, const std::string& str); +jstring ConvertUTF8ToJavaString(JNIEnv* env, const base::StringPiece& str); // Convert a Java string to UTF16. Returns a string16. string16 ConvertJavaStringToUTF16(JNIEnv* env, jstring str); diff --git a/base/android/path_utils.cc b/base/android/path_utils.cc index 623e030..dc45c28 100644 --- a/base/android/path_utils.cc +++ b/base/android/path_utils.cc @@ -6,7 +6,7 @@ #include "base/android/jni_android.h" #include "base/android/jni_string.h" -#include "base/android/scoped_java_reference.h" +#include "base/android/scoped_java_ref.h" #include "jni/path_utils_jni.h" @@ -15,14 +15,14 @@ namespace android { std::string GetDataDirectory() { JNIEnv* env = AttachCurrentThread(); - ScopedJavaReference<jstring> path(env, Java_PathUtils_getDataDirectory( + ScopedJavaLocalRef<jstring> path(env, Java_PathUtils_getDataDirectory( env, base::android::GetApplicationContext())); return base::android::ConvertJavaStringToUTF8(env, path.obj()); } std::string GetCacheDirectory() { JNIEnv* env = AttachCurrentThread(); - ScopedJavaReference<jstring> path(env, Java_PathUtils_getCacheDirectory( + ScopedJavaLocalRef<jstring> path(env, Java_PathUtils_getCacheDirectory( env, base::android::GetApplicationContext())); return base::android::ConvertJavaStringToUTF8(env, path.obj()); } diff --git a/base/android/scoped_java_global_reference.h b/base/android/scoped_java_global_reference.h deleted file mode 100644 index a5f33f0..0000000 --- a/base/android/scoped_java_global_reference.h +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_ANDROID_SCOPED_JAVA_GLOBAL_REFERENCE_H_ -#define BASE_ANDROID_SCOPED_JAVA_GLOBAL_REFERENCE_H_ - -#include <jni.h> -#include <stddef.h> - -#include "base/android/scoped_java_reference.h" -#include "base/basictypes.h" - -namespace base { -namespace android { - -// Holds a global reference to a Java object. The global reference is scoped -// to the lifetime of this object. Note that since a JNI Env is only suitable -// for use on a single thread, objects of this class must be created, used and -// destroyed on the same thread. -template<typename T> -class ScopedJavaGlobalReference { - public: - // Holds a NULL reference. - ScopedJavaGlobalReference() - : env_(NULL), - obj_(NULL) { - } - // Takes a new global reference to the Java object held by obj. - explicit ScopedJavaGlobalReference(const ScopedJavaReference<T>& obj) - : env_(obj.env()), - obj_(static_cast<T>(obj.env()->NewGlobalRef(obj.obj()))) { - } - ~ScopedJavaGlobalReference() { - Reset(); - } - - void Reset() { - if (env_ && obj_) - env_->DeleteGlobalRef(obj_); - env_ = NULL; - obj_ = NULL; - } - void Reset(const ScopedJavaGlobalReference& other) { - Reset(); - env_ = other.env_; - obj_ = other.env_ ? static_cast<T>(other.env_->NewGlobalRef(other.obj_)) : - NULL; - } - - T obj() const { return obj_; } - - private: - JNIEnv* env_; - T obj_; - - DISALLOW_COPY_AND_ASSIGN(ScopedJavaGlobalReference); -}; - -} // namespace android -} // namespace base - -#endif // BASE_ANDROID_SCOPED_JAVA_GLOBAL_REFERENCE_H_ diff --git a/base/android/scoped_java_ref.cc b/base/android/scoped_java_ref.cc new file mode 100644 index 0000000..da932f8 --- /dev/null +++ b/base/android/scoped_java_ref.cc @@ -0,0 +1,47 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/android/scoped_java_ref.h" + +namespace base { +namespace android { + +JavaRef<jobject>::JavaRef() : env_(NULL), obj_(NULL) {} + +JavaRef<jobject>::JavaRef(JNIEnv* env, jobject obj) + : env_(env), + obj_(obj) { + DCHECK_EQ(JNILocalRefType, env->GetObjectRefType(obj)); +} + +JavaRef<jobject>::~JavaRef() { +} + +void JavaRef<jobject>::SetNewLocalRef(JNIEnv* env, jobject obj) { + if (obj) + obj = env->NewLocalRef(obj); + if (obj_) + env_->DeleteLocalRef(obj_); + env_ = env; + obj_ = obj; +} + +void JavaRef<jobject>::SetNewGlobalRef(JNIEnv* env, jobject obj) { + if (obj) + obj = env->NewGlobalRef(obj); + if (obj_) + env_->DeleteGlobalRef(obj_); + env_ = env; + obj_ = obj; +} + +jobject JavaRef<jobject>::ReleaseInternal() { + jobject obj = obj_; + env_ = NULL; + obj_ = NULL; + return obj; +} + +} // namespace android +} // namespace base diff --git a/base/android/scoped_java_ref.h b/base/android/scoped_java_ref.h new file mode 100644 index 0000000..a74cef7 --- /dev/null +++ b/base/android/scoped_java_ref.h @@ -0,0 +1,175 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_ANDROID_SCOPED_JAVA_REF_H_ +#define BASE_ANDROID_SCOPED_JAVA_REF_H_ + +#include <jni.h> +#include <stddef.h> + +#include "base/logging.h" + +namespace base { +namespace android { + +// Forward declare the generic java reference template class. +template<typename T> class JavaRef; + +// Template specialization of JavaRef, which acts as the base class for all +// other JavaRef<> template types. This allows you to e.g. pass +// ScopedJavaLocalRef<jstring> into a function taking const JavaRef<jobject>& +template<> +class JavaRef<jobject> { + public: + JNIEnv* env() const { return env_; } + jobject obj() const { return obj_; } + + protected: + // Initializes a NULL reference. + JavaRef(); + + // Takes ownership of the |obj| reference passed; requires it to be a local + // reference type. + JavaRef(JNIEnv* env, jobject obj); + + ~JavaRef(); + + // The following are implementation detail convenience methods, for + // use by the sub-classes. + void SetNewLocalRef(JNIEnv* env, jobject obj); + void SetNewGlobalRef(JNIEnv* env, jobject obj); + jobject ReleaseInternal(); + + private: + JNIEnv* env_; + jobject obj_; + + DISALLOW_COPY_AND_ASSIGN(JavaRef); +}; + +// Generic base class for ScopedJavaLocalRef and ScopedJavaGlobalRef. Useful +// for allowing functions to accept a reference without having to mandate +// whether it is a local or global type. +template<typename T> +class JavaRef : public JavaRef<jobject> { + public: + T obj() const { return static_cast<T>(JavaRef<jobject>::obj()); } + + protected: + JavaRef() {} + ~JavaRef() {} + + JavaRef(JNIEnv* env, T obj) : JavaRef<jobject>(env, obj) {} + + private: + DISALLOW_COPY_AND_ASSIGN(JavaRef); +}; + +// Holds a local reference to a Java object. The local reference is scoped +// to the lifetime of this object. Note that since a JNI Env is only suitable +// for use on a single thread, objects of this class must be created, used and +// destroyed on the same thread. +// In general, this class should only be used as a stack-based object. If you +// wish to have the reference outlive the current callstack (e.g. as a class +// member) use ScopedJavaGlobalRef instead. +template<typename T> +class ScopedJavaLocalRef : public JavaRef<T> { + public: + ScopedJavaLocalRef() {} + + // Non-explicit copy constructor, to allow ScopedJavaLocalRef to be returned + // by value as this is the normal usage pattern. + ScopedJavaLocalRef(const ScopedJavaLocalRef<T>& other) { + this->Reset(other); + } + + template<typename U> + explicit ScopedJavaLocalRef(const U& other) { + this->Reset(other); + } + + // Assumes that |obj| is a local reference to a Java object and takes + // ownership of this local reference. + ScopedJavaLocalRef(JNIEnv* env, T obj) : JavaRef<T>(env, obj) {} + + ~ScopedJavaLocalRef() { + this->Reset(); + } + + // Overloaded assignment operator defined for consistency with the implicit + // copy constructor. + void operator=(const ScopedJavaLocalRef<T>& other) { + this->Reset(other); + } + + void Reset() { + this->SetNewLocalRef(NULL, NULL); + } + + template<typename U> + void Reset(const U& other) { + this->Reset(other.env(), other.obj()); + } + + template<typename U> + void Reset(JNIEnv* env, U obj) { + implicit_cast<T>(obj); // Ensure U is assignable to T + this->SetNewLocalRef(env, obj); + } + + // Releases the local reference to the caller. The caller *must* delete the + // local reference when it is done with it. + T Release() { + return static_cast<T>(this->ReleaseInternal()); + } +}; + +// Holds a global reference to a Java object. The global reference is scoped +// to the lifetime of this object. Note that since a JNI Env is only suitable +// for use on a single thread, objects of this class must be created, used and +// destroyed on the same thread. +template<typename T> +class ScopedJavaGlobalRef : public JavaRef<T> { + public: + ScopedJavaGlobalRef() {} + + explicit ScopedJavaGlobalRef(const ScopedJavaGlobalRef<T>& other) { + this->Reset(other); + } + + template<typename U> + explicit ScopedJavaGlobalRef(const U& other) { + this->Reset(other); + } + + ~ScopedJavaGlobalRef() { + this->Reset(); + } + + void Reset() { + this->SetNewGlobalRef(NULL, NULL); + } + + template<typename U> + void Reset(const U& other) { + this->Reset(other.env(), other.obj()); + } + + template<typename U> + void Reset(JNIEnv* env, U obj) { + implicit_cast<T>(obj); // Ensure U is assignable to T + this->SetNewGlobalRef(env, obj); + } + + // Releases the global reference to the caller. The caller *must* delete the + // global reference when it is done with it. + T Release() { + return static_cast<T>(this->ReleaseInternal()); + } +}; + +} // namespace android +} // namespace base + +#endif // BASE_ANDROID_SCOPED_JAVA_REF_H_ diff --git a/base/android/scoped_java_ref_unittest.cc b/base/android/scoped_java_ref_unittest.cc new file mode 100644 index 0000000..a6dfc7a --- /dev/null +++ b/base/android/scoped_java_ref_unittest.cc @@ -0,0 +1,114 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/android/scoped_java_ref.h" + +#include "base/android/jni_android.h" +#include "base/android/jni_string.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace base { +namespace android { + +namespace { +int g_local_refs = 0; +int g_global_refs = 0; + +jobject NewGlobalRef(JNIEnv* env, jobject obj) { + ++g_global_refs; + return AttachCurrentThread()->NewGlobalRef(obj); +} + +void DeleteGlobalRef(JNIEnv* env, jobject obj) { + --g_global_refs; + return AttachCurrentThread()->DeleteGlobalRef(obj); +} + +jobject NewLocalRef(JNIEnv* env, jobject obj) { + ++g_local_refs; + return AttachCurrentThread()->NewLocalRef(obj); +} + +void DeleteLocalRef(JNIEnv* env, jobject obj) { + --g_local_refs; + return AttachCurrentThread()->DeleteLocalRef(obj); +} +} // namespace + +class ScopedJavaRefTest : public testing::Test { + protected: + virtual void SetUp() { + g_local_refs = 0; + g_global_refs = 0; + JNIEnv* env = AttachCurrentThread(); + counting_env = *env; + counting_functions = *counting_env.functions; + counting_functions.NewGlobalRef = &NewGlobalRef; + counting_functions.DeleteGlobalRef = &DeleteGlobalRef; + counting_functions.NewLocalRef = &NewLocalRef; + counting_functions.DeleteLocalRef = &DeleteLocalRef; + counting_env.functions = &counting_functions; + } + + // Special JNI env configured in SetUp to count in and out all local & global + // reference instances. Be careful to only use this with the ScopedJavaRef + // classes under test, else it's easy to get system references counted in + // here too. + JNIEnv counting_env; + JNINativeInterface counting_functions; +}; + +// The main purpose of this is testing the various conversions compile. +TEST_F(ScopedJavaRefTest, Conversions) { + JNIEnv* env = AttachCurrentThread(); + ScopedJavaLocalRef<jstring> str(env, ConvertUTF8ToJavaString(env, "string")); + ScopedJavaGlobalRef<jstring> global(str); + { + ScopedJavaGlobalRef<jobject> global_obj(str); + ScopedJavaLocalRef<jobject> local_obj(global); + const JavaRef<jobject>& obj_ref1(str); + const JavaRef<jobject>& obj_ref2(global); + EXPECT_TRUE(env->IsSameObject(obj_ref1.obj(), obj_ref2.obj())); + EXPECT_TRUE(env->IsSameObject(global_obj.obj(), obj_ref2.obj())); + } + global.Reset(str); + const JavaRef<jstring>& str_ref = str; + EXPECT_EQ("string", ConvertJavaStringToUTF8(env, str_ref.obj())); + str.Reset(); +} + +TEST_F(ScopedJavaRefTest, RefCounts) { + ScopedJavaLocalRef<jstring> str; + str.Reset(&counting_env, ConvertUTF8ToJavaString(AttachCurrentThread(), + "string")); + EXPECT_EQ(1, g_local_refs); + EXPECT_EQ(0, g_global_refs); + + { + ScopedJavaGlobalRef<jstring> global_str(str); + ScopedJavaGlobalRef<jobject> global_obj(global_str); + EXPECT_EQ(1, g_local_refs); + EXPECT_EQ(2, g_global_refs); + + ScopedJavaLocalRef<jstring> str2(&counting_env, str.Release()); + EXPECT_EQ(1, g_local_refs); + { + ScopedJavaLocalRef<jstring> str3(str2); + EXPECT_EQ(2, g_local_refs); + } + EXPECT_EQ(1, g_local_refs); + str2.Reset(); + EXPECT_EQ(0, g_local_refs); + global_str.Reset(); + EXPECT_EQ(1, g_global_refs); + ScopedJavaGlobalRef<jobject> global_obj2(global_obj); + EXPECT_EQ(2, g_global_refs); + } + + EXPECT_EQ(0, g_local_refs); + EXPECT_EQ(0, g_global_refs); +} + +} // namespace android +} // namespace base diff --git a/base/android/scoped_java_reference.h b/base/android/scoped_java_reference.h deleted file mode 100644 index 70e8610..0000000 --- a/base/android/scoped_java_reference.h +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_ANDROID_SCOPED_JAVA_REFERENCE_H_ -#define BASE_ANDROID_SCOPED_JAVA_REFERENCE_H_ - -#include <jni.h> -#include <stddef.h> - -namespace base { -namespace android { - -// Holds a local reference to a Java object. The local reference is scoped -// to the lifetime of this object. Note that since a JNI Env is only suitable -// for use on a single thread, objects of this class must be created, used and -// destroyed on the same thread. -template<typename T> -class ScopedJavaReference { - public: - // Holds a NULL reference. - ScopedJavaReference() - : env_(NULL), - obj_(NULL) { - } - // Assumes that obj is a local reference to a Java object and takes ownership - // of this local reference. - ScopedJavaReference(JNIEnv* env, T obj) - : env_(env), - obj_(obj) { - } - // Takes a new local reference to the Java object held by other. - ScopedJavaReference(const ScopedJavaReference& other) - : env_(other.env_), - obj_(other.obj_ ? static_cast<T>(other.env_->NewLocalRef(other.obj_)) : - NULL) { - } - ~ScopedJavaReference() { - if (obj_) - env_->DeleteLocalRef(obj_); - } - - void operator=(const ScopedJavaReference& other) { - if (obj_) - env_->DeleteLocalRef(obj_); - env_ = other.env_; - obj_ = other.obj_ ? static_cast<T>(env_->NewLocalRef(other.obj_)) : NULL; - } - - JNIEnv* env() const { return env_; } - T obj() const { return obj_; } - - // Releases the local reference to the caller. The caller *must* delete the - // local reference when it is done with it. - T Release() { - jobject obj = obj_; - obj_ = NULL; - return obj; - } - - private: - JNIEnv* env_; - T obj_; -}; - -} // namespace android -} // namespace base - -#endif // BASE_ANDROID_SCOPED_JAVA_REFERENCE_H_ |