scoped_java_ref.h revision 5821806d5e7f356e8fa4b058a389a808ea183019
1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef BASE_ANDROID_SCOPED_JAVA_REF_H_
6#define BASE_ANDROID_SCOPED_JAVA_REF_H_
7
8#include <jni.h>
9#include <stddef.h>
10
11#include "base/base_export.h"
12#include "base/basictypes.h"
13
14namespace base {
15namespace android {
16
17// Forward declare the generic java reference template class.
18template<typename T> class JavaRef;
19
20// Template specialization of JavaRef, which acts as the base class for all
21// other JavaRef<> template types. This allows you to e.g. pass
22// ScopedJavaLocalRef<jstring> into a function taking const JavaRef<jobject>&
23template<>
24class BASE_EXPORT JavaRef<jobject> {
25 public:
26  jobject obj() const { return obj_; }
27
28  bool is_null() const { return obj_ == NULL; }
29
30 protected:
31  // Initializes a NULL reference.
32  JavaRef();
33
34  // Takes ownership of the |obj| reference passed; requires it to be a local
35  // reference type.
36  JavaRef(JNIEnv* env, jobject obj);
37
38  ~JavaRef();
39
40  // The following are implementation detail convenience methods, for
41  // use by the sub-classes.
42  JNIEnv* SetNewLocalRef(JNIEnv* env, jobject obj);
43  void SetNewGlobalRef(JNIEnv* env, jobject obj);
44  void ResetLocalRef(JNIEnv* env);
45  void ResetGlobalRef();
46  jobject ReleaseInternal();
47
48 private:
49  jobject obj_;
50
51  DISALLOW_COPY_AND_ASSIGN(JavaRef);
52};
53
54// Generic base class for ScopedJavaLocalRef and ScopedJavaGlobalRef. Useful
55// for allowing functions to accept a reference without having to mandate
56// whether it is a local or global type.
57template<typename T>
58class JavaRef : public JavaRef<jobject> {
59 public:
60  T obj() const { return static_cast<T>(JavaRef<jobject>::obj()); }
61
62 protected:
63  JavaRef() {}
64  ~JavaRef() {}
65
66  JavaRef(JNIEnv* env, T obj) : JavaRef<jobject>(env, obj) {}
67
68 private:
69  DISALLOW_COPY_AND_ASSIGN(JavaRef);
70};
71
72// Holds a local reference to a Java object. The local reference is scoped
73// to the lifetime of this object.
74// Instances of this class may hold onto any JNIEnv passed into it until
75// destroyed. Therefore, since a JNIEnv is only suitable for use on a single
76// thread, objects of this class must be created, used, and destroyed, on a
77// single thread.
78// Therefore, this class should only be used as a stack-based object and from a
79// single thread. If you wish to have the reference outlive the current
80// callstack (e.g. as a class member) or you wish to pass it across threads,
81// use a ScopedJavaGlobalRef instead.
82template<typename T>
83class ScopedJavaLocalRef : public JavaRef<T> {
84 public:
85  ScopedJavaLocalRef() : env_(NULL) {}
86
87  // Non-explicit copy constructor, to allow ScopedJavaLocalRef to be returned
88  // by value as this is the normal usage pattern.
89  ScopedJavaLocalRef(const ScopedJavaLocalRef<T>& other)
90      : env_(other.env_) {
91    this->SetNewLocalRef(env_, other.obj());
92  }
93
94  template<typename U>
95  explicit ScopedJavaLocalRef(const U& other)
96      : env_(NULL) {
97    this->Reset(other);
98  }
99
100  // Assumes that |obj| is a local reference to a Java object and takes
101  // ownership  of this local reference.
102  ScopedJavaLocalRef(JNIEnv* env, T obj) : JavaRef<T>(env, obj), env_(env) {}
103
104  ~ScopedJavaLocalRef() {
105    this->Reset();
106  }
107
108  // Overloaded assignment operator defined for consistency with the implicit
109  // copy constructor.
110  void operator=(const ScopedJavaLocalRef<T>& other) {
111    this->Reset(other);
112  }
113
114  void Reset() {
115    this->ResetLocalRef(env_);
116  }
117
118  template<typename U>
119  void Reset(const ScopedJavaLocalRef<U>& other) {
120    // We can copy over env_ here as |other| instance must be from the same
121    // thread as |this| local ref. (See class comment for multi-threading
122    // limitations, and alternatives).
123    this->Reset(other.env_, other.obj());
124  }
125
126  template<typename U>
127  void Reset(const U& other) {
128    // If |env_| was not yet set (is still NULL) it will be attached to the
129    // current thread in SetNewLocalRef().
130    this->Reset(env_, other.obj());
131  }
132
133  template<typename U>
134  void Reset(JNIEnv* env, U obj) {
135    implicit_cast<T>(obj);  // Ensure U is assignable to T
136    env_ = this->SetNewLocalRef(env, obj);
137  }
138
139  // Releases the local reference to the caller. The caller *must* delete the
140  // local reference when it is done with it.
141  T Release() {
142    return static_cast<T>(this->ReleaseInternal());
143  }
144
145 private:
146  // This class is only good for use on the thread it was created on so
147  // it's safe to cache the non-threadsafe JNIEnv* inside this object.
148  JNIEnv* env_;
149};
150
151// Holds a global reference to a Java object. The global reference is scoped
152// to the lifetime of this object. This class does not hold onto any JNIEnv*
153// passed to it, hence it is safe to use across threads (within the constraints
154// imposed by the underlying Java object that it references).
155template<typename T>
156class ScopedJavaGlobalRef : public JavaRef<T> {
157 public:
158  ScopedJavaGlobalRef() {}
159
160  explicit ScopedJavaGlobalRef(const ScopedJavaGlobalRef<T>& other) {
161    this->Reset(other);
162  }
163
164  template<typename U>
165  explicit ScopedJavaGlobalRef(const U& other) {
166    this->Reset(other);
167  }
168
169  ~ScopedJavaGlobalRef() {
170    this->Reset();
171  }
172
173  void Reset() {
174    this->ResetGlobalRef();
175  }
176
177  template<typename U>
178  void Reset(const U& other) {
179    this->Reset(NULL, other.obj());
180  }
181
182  template<typename U>
183  void Reset(JNIEnv* env, U obj) {
184    implicit_cast<T>(obj);  // Ensure U is assignable to T
185    this->SetNewGlobalRef(env, obj);
186  }
187
188  // Releases the global reference to the caller. The caller *must* delete the
189  // global reference when it is done with it.
190  T Release() {
191    return static_cast<T>(this->ReleaseInternal());
192  }
193};
194
195}  // namespace android
196}  // namespace base
197
198#endif  // BASE_ANDROID_SCOPED_JAVA_REF_H_
199