Skip to content

Commit 0c728c1

Browse files
wilhuffa-maurice
authored andcommitted
Convert Timestamp to the new JNI framework
PiperOrigin-RevId: 329814232
1 parent 435481d commit 0c728c1

File tree

7 files changed

+64
-91
lines changed

7 files changed

+64
-91
lines changed

firestore/src/android/field_value_android.cc

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -99,10 +99,9 @@ FieldValueInternal::FieldValueInternal(double value)
9999

100100
FieldValueInternal::FieldValueInternal(Timestamp value)
101101
: cached_type_(Type::kTimestamp) {
102-
JNIEnv* env = firestore_->app()->GetJNIEnv();
103-
jobject obj = TimestampInternal::TimestampToJavaTimestamp(env, value);
104-
obj_ = env->NewGlobalRef(obj);
105-
env->DeleteLocalRef(obj);
102+
Env env;
103+
Local<TimestampInternal> obj = TimestampInternal::Create(env, value);
104+
obj_ = env.get()->NewGlobalRef(obj.get());
106105
}
107106

108107
FieldValueInternal::FieldValueInternal(std::string value)
@@ -194,7 +193,7 @@ Type FieldValueInternal::type() const {
194193
cached_type_ = Type::kDouble;
195194
return Type::kDouble;
196195
}
197-
if (env->IsInstanceOf(obj_, TimestampInternal::GetClass())) {
196+
if (env->IsInstanceOf(obj_, TimestampInternal::GetClass().get())) {
198197
cached_type_ = Type::kTimestamp;
199198
return Type::kTimestamp;
200199
}
@@ -271,17 +270,17 @@ double FieldValueInternal::double_value() const {
271270
}
272271

273272
Timestamp FieldValueInternal::timestamp_value() const {
274-
JNIEnv* env = firestore_->app()->GetJNIEnv();
273+
Env env;
275274

276275
// Make sure this instance is of correct type.
277276
if (cached_type_ == Type::kNull) {
278-
FIREBASE_ASSERT(env->IsInstanceOf(obj_, TimestampInternal::GetClass()));
277+
FIREBASE_ASSERT(env.IsInstanceOf(obj_, TimestampInternal::GetClass()));
279278
cached_type_ = Type::kTimestamp;
280279
} else {
281280
FIREBASE_ASSERT(cached_type_ == Type::kTimestamp);
282281
}
283282

284-
return TimestampInternal::JavaTimestampToTimestamp(env, obj_);
283+
return TimestampInternal(obj_).ToPublic(env);
285284
}
286285

287286
std::string FieldValueInternal::string_value() const {

firestore/src/android/firestore_android.cc

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,6 @@ bool FirestoreInternal::Initialize(App* app) {
170170
ListenerRegistrationInternal::Initialize(app) &&
171171
QueryInternal::Initialize(app) &&
172172
QuerySnapshotInternal::Initialize(app) &&
173-
TimestampInternal::Initialize(app) &&
174173
TransactionInternal::Initialize(app) && Wrapper::Initialize(app) &&
175174
// Initialize those embedded Firestore internal classes.
176175
InitializeEmbeddedClasses(app))) {
@@ -204,6 +203,7 @@ bool FirestoreInternal::Initialize(App* app) {
204203
SettingsInternal::Initialize(loader);
205204
SnapshotMetadataInternal::Initialize(loader);
206205
SourceInternal::Initialize(loader);
206+
TimestampInternal::Initialize(loader);
207207
WriteBatchInternal::Initialize(loader);
208208
if (!loader.ok()) {
209209
ReleaseClasses(app);
@@ -258,7 +258,6 @@ void FirestoreInternal::ReleaseClasses(App* app) {
258258
ListenerRegistrationInternal::Terminate(app);
259259
QueryInternal::Terminate(app);
260260
QuerySnapshotInternal::Terminate(app);
261-
TimestampInternal::Terminate(app);
262261
TransactionInternal::Terminate(app);
263262
Wrapper::Terminate(app);
264263
}

firestore/src/android/timestamp_android.cc

Lines changed: 27 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,65 +1,44 @@
11
#include "firestore/src/android/timestamp_android.h"
22

3-
#include <stdint.h>
4-
5-
#include "app/src/util_android.h"
6-
#include "firestore/src/android/util_android.h"
3+
#include "firestore/src/jni/env.h"
4+
#include "firestore/src/jni/loader.h"
75

86
namespace firebase {
97
namespace firestore {
8+
namespace {
109

11-
// clang-format off
12-
#define TIMESTAMP_METHODS(X) \
13-
X(Constructor, "<init>", "(JI)V", util::kMethodTypeInstance), \
14-
X(GetSeconds, "getSeconds", "()J"), \
15-
X(GetNanoseconds, "getNanoseconds", "()I")
16-
// clang-format on
10+
using jni::Class;
11+
using jni::Constructor;
12+
using jni::Env;
13+
using jni::Local;
14+
using jni::Method;
1715

18-
METHOD_LOOKUP_DECLARATION(timestamp, TIMESTAMP_METHODS)
19-
METHOD_LOOKUP_DEFINITION(timestamp,
20-
PROGUARD_KEEP_CLASS "com/google/firebase/Timestamp",
21-
TIMESTAMP_METHODS)
16+
constexpr char kClassName[] =
17+
PROGUARD_KEEP_CLASS "com/google/firebase/Timestamp";
18+
Constructor<TimestampInternal> kConstructor("(JI)V");
19+
Method<int64_t> kGetSeconds("getSeconds", "()J");
20+
Method<int32_t> kGetNanoseconds("getNanoseconds", "()I");
2221

23-
/* static */
24-
jobject TimestampInternal::TimestampToJavaTimestamp(
25-
JNIEnv* env, const Timestamp& timestamp) {
26-
jobject result = env->NewObject(
27-
timestamp::GetClass(), timestamp::GetMethodId(timestamp::kConstructor),
28-
static_cast<jlong>(timestamp.seconds()),
29-
static_cast<jint>(timestamp.nanoseconds()));
30-
CheckAndClearJniExceptions(env);
31-
return result;
32-
}
22+
jclass g_clazz = nullptr;
23+
24+
} // namespace
3325

34-
/* static */
35-
Timestamp TimestampInternal::JavaTimestampToTimestamp(JNIEnv* env,
36-
jobject obj) {
37-
jlong seconds =
38-
env->CallLongMethod(obj, timestamp::GetMethodId(timestamp::kGetSeconds));
39-
jint nanoseconds = env->CallIntMethod(
40-
obj, timestamp::GetMethodId(timestamp::kGetNanoseconds));
41-
CheckAndClearJniExceptions(env);
42-
return Timestamp{static_cast<int64_t>(seconds),
43-
static_cast<int32_t>(nanoseconds)};
26+
void TimestampInternal::Initialize(jni::Loader& loader) {
27+
g_clazz =
28+
loader.LoadClass(kClassName, kConstructor, kGetSeconds, kGetNanoseconds);
4429
}
4530

46-
/* static */
47-
jclass TimestampInternal::GetClass() { return timestamp::GetClass(); }
31+
Class TimestampInternal::GetClass() { return Class(g_clazz); }
4832

49-
/* static */
50-
bool TimestampInternal::Initialize(App* app) {
51-
JNIEnv* env = app->GetJNIEnv();
52-
jobject activity = app->activity();
53-
bool result = timestamp::CacheMethodIds(env, activity);
54-
util::CheckAndClearJniExceptions(env);
55-
return result;
33+
Local<TimestampInternal> TimestampInternal::Create(Env& env,
34+
const Timestamp& timestamp) {
35+
return env.New(kConstructor, timestamp.seconds(), timestamp.nanoseconds());
5636
}
5737

58-
/* static */
59-
void TimestampInternal::Terminate(App* app) {
60-
JNIEnv* env = app->GetJNIEnv();
61-
timestamp::ReleaseClass(env);
62-
util::CheckAndClearJniExceptions(env);
38+
Timestamp TimestampInternal::ToPublic(Env& env) const {
39+
int64_t seconds = env.Call(*this, kGetSeconds);
40+
int32_t nanoseconds = env.Call(*this, kGetNanoseconds);
41+
return Timestamp(seconds, nanoseconds);
6342
}
6443

6544
} // namespace firestore

firestore/src/android/timestamp_android.h

Lines changed: 12 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,30 @@
11
#ifndef FIREBASE_FIRESTORE_CLIENT_CPP_SRC_ANDROID_TIMESTAMP_ANDROID_H_
22
#define FIREBASE_FIRESTORE_CLIENT_CPP_SRC_ANDROID_TIMESTAMP_ANDROID_H_
33

4-
#include <jni.h>
5-
6-
#include "app/src/include/firebase/app.h"
4+
#include "firestore/src/jni/jni_fwd.h"
5+
#include "firestore/src/jni/object.h"
76
#include "firebase/firestore/timestamp.h"
87

98
namespace firebase {
109
namespace firestore {
1110

12-
// This is the non-wrapper Android implementation of Timestamp. Since Timestamp
13-
// has most of their method inlined, we use it directly instead of wrapping
14-
// around a Java Timestamp object. We still need the helper functions to convert
15-
// between the two types. In addition, we also need proper initializer and
16-
// terminator for the Java class cache/uncache.
17-
class TimestampInternal {
11+
/** A C++ proxy for a Java `Timestamp`. */
12+
class TimestampInternal : public jni::Object {
1813
public:
1914
using ApiType = Timestamp;
2015

21-
// Convert a C++ Timestamp into a Java Timestamp.
22-
static jobject TimestampToJavaTimestamp(JNIEnv* env,
23-
const Timestamp& timestamp);
16+
using jni::Object::Object;
2417

25-
// Convert a Java Timestamp into a C++ Timestamp.
26-
static Timestamp JavaTimestampToTimestamp(JNIEnv* env, jobject obj);
18+
static void Initialize(jni::Loader& loader);
2719

28-
// Gets the class object of Java Timestamp class.
29-
static jclass GetClass();
20+
static jni::Class GetClass();
3021

31-
private:
32-
friend class FirestoreInternal;
22+
/** Creates a C++ proxy for a Java `Timestamp` object. */
23+
static jni::Local<TimestampInternal> Create(jni::Env& env,
24+
const Timestamp& timestamp);
3325

34-
static bool Initialize(App* app);
35-
static void Terminate(App* app);
26+
/** Converts a Java `Timestamp` into a public C++ `Timestamp`. */
27+
Timestamp ToPublic(jni::Env& env) const;
3628
};
3729

3830
} // namespace firestore

firestore/src/jni/env.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,9 @@ class Env {
158158
Local<Class> GetObjectClass(const Object& object);
159159

160160
bool IsInstanceOf(const Object& object, const Class& clazz);
161+
bool IsInstanceOf(jobject object, const Class& clazz) {
162+
return IsInstanceOf(Object(object), clazz);
163+
}
161164

162165
bool IsSameObject(const Object& object1, const Object& object2);
163166

firestore/src/jni/loader.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,9 +91,10 @@ class Loader {
9191
* Loads a Java class and all its members in a single invocation.
9292
*/
9393
template <typename... Members>
94-
void LoadClass(const char* name, Members&&... members) {
95-
LoadClass(name);
94+
jclass LoadClass(const char* name, Members&&... members) {
95+
jclass result = LoadClass(name);
9696
LoadAll(Forward<Members>(members)...);
97+
return result;
9798
}
9899

99100
/**
Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,26 @@
11
#include "firestore/src/android/timestamp_android.h"
22

3-
#include <jni.h>
4-
3+
#include "firestore/src/jni/env.h"
54
#include "firestore/src/tests/firestore_integration_test.h"
6-
#include "testing/base/public/gmock.h"
75
#include "gtest/gtest.h"
86
#include "firebase/firestore/timestamp.h"
97

108
namespace firebase {
119
namespace firestore {
10+
namespace {
11+
12+
using jni::Env;
1213

13-
TEST_F(FirestoreIntegrationTest, Converter) {
14-
JNIEnv* env = app()->GetJNIEnv();
14+
using TimestampTest = FirestoreIntegrationTest;
1515

16-
const Timestamp timestamp{1234, 5678};
17-
jobject java_timestamp =
18-
TimestampInternal::TimestampToJavaTimestamp(env, timestamp);
19-
EXPECT_EQ(timestamp,
20-
TimestampInternal::JavaTimestampToTimestamp(env, java_timestamp));
16+
TEST_F(TimestampTest, Converts) {
17+
Env env;
2118

22-
env->DeleteLocalRef(java_timestamp);
19+
Timestamp timestamp{1234, 5678};
20+
auto java_timestamp = TimestampInternal::Create(env, timestamp);
21+
EXPECT_EQ(timestamp, java_timestamp.ToPublic(env));
2322
}
2423

24+
} // namespace
2525
} // namespace firestore
2626
} // namespace firebase

0 commit comments

Comments
 (0)