1*65c59e02SInna Palant /*
2*65c59e02SInna Palant * Copyright (c) Facebook, Inc. and its affiliates.
3*65c59e02SInna Palant *
4*65c59e02SInna Palant * Licensed under the Apache License, Version 2.0 (the "License");
5*65c59e02SInna Palant * you may not use this file except in compliance with the License.
6*65c59e02SInna Palant * You may obtain a copy of the License at
7*65c59e02SInna Palant *
8*65c59e02SInna Palant * http://www.apache.org/licenses/LICENSE-2.0
9*65c59e02SInna Palant *
10*65c59e02SInna Palant * Unless required by applicable law or agreed to in writing, software
11*65c59e02SInna Palant * distributed under the License is distributed on an "AS IS" BASIS,
12*65c59e02SInna Palant * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*65c59e02SInna Palant * See the License for the specific language governing permissions and
14*65c59e02SInna Palant * limitations under the License.
15*65c59e02SInna Palant */
16*65c59e02SInna Palant
17*65c59e02SInna Palant #include <fbjni/fbjni.h>
18*65c59e02SInna Palant #include <condition_variable>
19*65c59e02SInna Palant #include <mutex>
20*65c59e02SInna Palant
21*65c59e02SInna Palant using namespace facebook::jni;
22*65c59e02SInna Palant
23*65c59e02SInna Palant class TestException : public std::runtime_error {
24*65c59e02SInna Palant public:
TestException()25*65c59e02SInna Palant TestException() : std::runtime_error("fail") {}
26*65c59e02SInna Palant };
27*65c59e02SInna Palant
28*65c59e02SInna Palant // The C++ half of a hybrid class must extend HybridClass like this.
29*65c59e02SInna Palant // HybridClass is default constructible.
30*65c59e02SInna Palant class TestHybridClass : public facebook::jni::HybridClass<TestHybridClass> {
31*65c59e02SInna Palant public:
32*65c59e02SInna Palant static constexpr const char* const kJavaDescriptor =
33*65c59e02SInna Palant "Lcom/facebook/jni/HybridTests$TestHybridClass;";
34*65c59e02SInna Palant
TestHybridClass()35*65c59e02SInna Palant TestHybridClass() {}
36*65c59e02SInna Palant
TestHybridClass(int i,std::string s,bool b)37*65c59e02SInna Palant TestHybridClass(int i, std::string s, bool b)
38*65c59e02SInna Palant : i_(i), s_(std::move(s)), b_(b) {}
39*65c59e02SInna Palant
40*65c59e02SInna Palant // The C++ implementation of initHybrid must be a static C++ method,
41*65c59e02SInna Palant // since it has no C++ instance (it creates it). But it's a normal
42*65c59e02SInna Palant // java method, because it gets a java this passed in (which is
43*65c59e02SInna Palant // often unused). It must call makeCxxInstance and return its
44*65c59e02SInna Palant // result.
45*65c59e02SInna Palant static jhybriddata
initHybrid(alias_ref<jhybridobject>,jint i,jstring s,jboolean b)46*65c59e02SInna Palant initHybrid(alias_ref<jhybridobject>, jint i, jstring s, jboolean b) {
47*65c59e02SInna Palant // The arguments will be forwarded to the ctor, and the result
48*65c59e02SInna Palant // will be saved in mHybridPointer in the java object.
49*65c59e02SInna Palant return makeCxxInstance(i, wrap_alias(s)->toStdString(), b).release();
50*65c59e02SInna Palant }
initHybrid2(alias_ref<jhybridobject>)51*65c59e02SInna Palant static local_ref<jhybriddata> initHybrid2(alias_ref<jhybridobject>) {
52*65c59e02SInna Palant return makeCxxInstance();
53*65c59e02SInna Palant }
54*65c59e02SInna Palant // It's also ok to make initHybrid work like a factory, which
55*65c59e02SInna Palant // eliminates the need to define a ctor and reduces boilerplate
56*65c59e02SInna Palant // code. This is a member, so fields can be initialized directly.
57*65c59e02SInna Palant static local_ref<jhybriddata>
initHybrid3(alias_ref<jhybridobject>,std::string s,int i,bool b)58*65c59e02SInna Palant initHybrid3(alias_ref<jhybridobject>, std::string s, int i, bool b) {
59*65c59e02SInna Palant auto cxxPart = std::unique_ptr<TestHybridClass>(new TestHybridClass);
60*65c59e02SInna Palant cxxPart->s_ = std::move(s);
61*65c59e02SInna Palant cxxPart->i_ = i;
62*65c59e02SInna Palant cxxPart->b_ = b;
63*65c59e02SInna Palant return makeHybridData(std::move(cxxPart));
64*65c59e02SInna Palant }
65*65c59e02SInna Palant
getInt()66*65c59e02SInna Palant jint getInt() {
67*65c59e02SInna Palant return i_;
68*65c59e02SInna Palant }
69*65c59e02SInna Palant
getString()70*65c59e02SInna Palant std::string getString() {
71*65c59e02SInna Palant return s_;
72*65c59e02SInna Palant }
73*65c59e02SInna Palant
getCharString()74*65c59e02SInna Palant const char* getCharString() {
75*65c59e02SInna Palant return s_.c_str();
76*65c59e02SInna Palant }
77*65c59e02SInna Palant
setBoth(int i,std::string s)78*65c59e02SInna Palant void setBoth(int i, std::string s) {
79*65c59e02SInna Palant i_ = i;
80*65c59e02SInna Palant s_ = s;
81*65c59e02SInna Palant }
82*65c59e02SInna Palant
copy1(alias_ref<jhybridobject> other)83*65c59e02SInna Palant bool copy1(alias_ref<jhybridobject> other) {
84*65c59e02SInna Palant i_ = cthis(other)->i_;
85*65c59e02SInna Palant s_ = cthis(other)->s_;
86*65c59e02SInna Palant return true;
87*65c59e02SInna Palant }
88*65c59e02SInna Palant
89*65c59e02SInna Palant // This returns a boolean to test more code paths, not for any
90*65c59e02SInna Palant // functional reason.
copy2(TestHybridClass * other)91*65c59e02SInna Palant jboolean copy2(TestHybridClass* other) {
92*65c59e02SInna Palant i_ = other->i_;
93*65c59e02SInna Palant s_ = other->s_;
94*65c59e02SInna Palant return true;
95*65c59e02SInna Palant }
96*65c59e02SInna Palant
oops()97*65c59e02SInna Palant void oops() {
98*65c59e02SInna Palant throw TestException();
99*65c59e02SInna Palant }
100*65c59e02SInna Palant
setGlobal(alias_ref<jstring> str)101*65c59e02SInna Palant void setGlobal(alias_ref<jstring> str) {
102*65c59e02SInna Palant global_ = make_global(str);
103*65c59e02SInna Palant }
104*65c59e02SInna Palant
getGlobal1()105*65c59e02SInna Palant global_ref<jstring> getGlobal1() {
106*65c59e02SInna Palant return global_;
107*65c59e02SInna Palant }
108*65c59e02SInna Palant
getGlobal2()109*65c59e02SInna Palant const global_ref<jstring>& getGlobal2() {
110*65c59e02SInna Palant return global_;
111*65c59e02SInna Palant }
112*65c59e02SInna Palant
makeWithTwo(alias_ref<jclass> jthis)113*65c59e02SInna Palant static jhybridobject makeWithTwo(alias_ref<jclass> jthis) {
114*65c59e02SInna Palant // The args are passed to java, with autoconversion.
115*65c59e02SInna Palant return newObjectJavaArgs(2, "two", true).release();
116*65c59e02SInna Palant }
117*65c59e02SInna Palant
makeWithThree(alias_ref<jclass> jthis)118*65c59e02SInna Palant static local_ref<jhybridobject> makeWithThree(alias_ref<jclass> jthis) {
119*65c59e02SInna Palant // The args are passed to C++ initialization directly.
120*65c59e02SInna Palant return newObjectCxxArgs(3, "three", true);
121*65c59e02SInna Palant }
122*65c59e02SInna Palant
mapException(std::exception_ptr ex)123*65c59e02SInna Palant static void mapException(std::exception_ptr ex) {
124*65c59e02SInna Palant try {
125*65c59e02SInna Palant std::rethrow_exception(ex);
126*65c59e02SInna Palant } catch (const TestException& ex) {
127*65c59e02SInna Palant throwNewJavaException("java/lang/ArrayStoreException", "");
128*65c59e02SInna Palant }
129*65c59e02SInna Palant }
130*65c59e02SInna Palant
autoconvertMany(alias_ref<jclass>)131*65c59e02SInna Palant static void autoconvertMany(alias_ref<jclass>) {
132*65c59e02SInna Palant // Autoconversion to jstring creates a local ref. Make sure is is
133*65c59e02SInna Palant // released properly. The default local table size is 512.
134*65c59e02SInna Palant for (int i = 0; i < 1000; ++i) {
135*65c59e02SInna Palant newObjectJavaArgs(1000, "thousand", false);
136*65c59e02SInna Palant newObjectJavaArgs(1001, make_jstring("thousand+1"), false);
137*65c59e02SInna Palant }
138*65c59e02SInna Palant }
139*65c59e02SInna Palant
140*65c59e02SInna Palant // Declaring a register function for each class makes it easy to
141*65c59e02SInna Palant // manage the process.
registerNatives()142*65c59e02SInna Palant static void registerNatives() {
143*65c59e02SInna Palant registerHybrid({
144*65c59e02SInna Palant // Test registration of static method returning void.
145*65c59e02SInna Palant makeNativeMethod("initHybrid", TestHybridClass::initHybrid),
146*65c59e02SInna Palant // overloaded members are ugly to get pointers to. Use a
147*65c59e02SInna Palant // different name for each C++ method to keep things readable.
148*65c59e02SInna Palant makeNativeMethod("initHybrid", TestHybridClass::initHybrid2),
149*65c59e02SInna Palant makeNativeMethod("initHybrid", TestHybridClass::initHybrid3),
150*65c59e02SInna Palant // C++ members can be registered directly. The C++ instance
151*65c59e02SInna Palant // created by makeCxxInstance will be retrieved from the
152*65c59e02SInna Palant // HybridData, and the method will be invoked with the
153*65c59e02SInna Palant // arguments passed to java. These test registration of
154*65c59e02SInna Palant // method pointers returning non-void.
155*65c59e02SInna Palant makeNativeMethod("getInt", TestHybridClass::getInt),
156*65c59e02SInna Palant makeNativeMethod("getString", TestHybridClass::getString),
157*65c59e02SInna Palant makeNativeMethod("getCharString", TestHybridClass::getCharString),
158*65c59e02SInna Palant makeNativeMethod("setBoth", TestHybridClass::setBoth),
159*65c59e02SInna Palant makeNativeMethod("copy1", TestHybridClass::copy1),
160*65c59e02SInna Palant makeNativeMethod("copy2", TestHybridClass::copy2),
161*65c59e02SInna Palant makeNativeMethod("oops", TestHybridClass::oops),
162*65c59e02SInna Palant makeNativeMethod("setGlobal", TestHybridClass::setGlobal),
163*65c59e02SInna Palant makeNativeMethod("getGlobal1", TestHybridClass::getGlobal1),
164*65c59e02SInna Palant makeNativeMethod("getGlobal2", TestHybridClass::getGlobal2),
165*65c59e02SInna Palant makeNativeMethod("makeWithTwo", TestHybridClass::makeWithTwo),
166*65c59e02SInna Palant makeNativeMethod("makeWithThree", TestHybridClass::makeWithThree),
167*65c59e02SInna Palant makeNativeMethod("autoconvertMany", TestHybridClass::autoconvertMany),
168*65c59e02SInna Palant });
169*65c59e02SInna Palant }
170*65c59e02SInna Palant
171*65c59e02SInna Palant private:
172*65c59e02SInna Palant friend HybridBase;
173*65c59e02SInna Palant
174*65c59e02SInna Palant int i_ = 0;
175*65c59e02SInna Palant std::string s_;
176*65c59e02SInna Palant bool b_ = false;
177*65c59e02SInna Palant global_ref<jstring> global_;
178*65c59e02SInna Palant };
179*65c59e02SInna Palant
180*65c59e02SInna Palant class AbstractTestHybrid
181*65c59e02SInna Palant : public facebook::jni::HybridClass<AbstractTestHybrid> {
182*65c59e02SInna Palant public:
183*65c59e02SInna Palant static constexpr const char* const kJavaDescriptor =
184*65c59e02SInna Palant "Lcom/facebook/jni/HybridTests$AbstractTestHybrid;";
185*65c59e02SInna Palant
AbstractTestHybrid(int nn)186*65c59e02SInna Palant AbstractTestHybrid(int nn) : nativeNum_(nn) {}
187*65c59e02SInna Palant
nativeNum()188*65c59e02SInna Palant int nativeNum() {
189*65c59e02SInna Palant return nativeNum_;
190*65c59e02SInna Palant }
191*65c59e02SInna Palant // This is different than the java method!
192*65c59e02SInna Palant virtual int sum() = 0;
193*65c59e02SInna Palant
registerNatives()194*65c59e02SInna Palant static void registerNatives() {
195*65c59e02SInna Palant registerHybrid({
196*65c59e02SInna Palant makeNativeMethod("nativeNum", AbstractTestHybrid::nativeNum),
197*65c59e02SInna Palant });
198*65c59e02SInna Palant }
199*65c59e02SInna Palant
200*65c59e02SInna Palant private:
201*65c59e02SInna Palant int nativeNum_;
202*65c59e02SInna Palant };
203*65c59e02SInna Palant
204*65c59e02SInna Palant class ConcreteTestHybrid
205*65c59e02SInna Palant : public facebook::jni::
206*65c59e02SInna Palant HybridClass<ConcreteTestHybrid, AbstractTestHybrid> {
207*65c59e02SInna Palant public:
208*65c59e02SInna Palant static constexpr const char* const kJavaDescriptor =
209*65c59e02SInna Palant "Lcom/facebook/jni/HybridTests$ConcreteTestHybrid;";
210*65c59e02SInna Palant
initHybrid(alias_ref<jclass>,int nn,int cn)211*65c59e02SInna Palant static local_ref<jhybriddata> initHybrid(alias_ref<jclass>, int nn, int cn) {
212*65c59e02SInna Palant return makeCxxInstance(nn, cn);
213*65c59e02SInna Palant }
214*65c59e02SInna Palant
concreteNum()215*65c59e02SInna Palant int concreteNum() {
216*65c59e02SInna Palant return concreteNum_;
217*65c59e02SInna Palant }
sum()218*65c59e02SInna Palant int sum() override {
219*65c59e02SInna Palant return nativeNum() + concreteNum();
220*65c59e02SInna Palant }
221*65c59e02SInna Palant
registerNatives()222*65c59e02SInna Palant static void registerNatives() {
223*65c59e02SInna Palant registerHybrid({
224*65c59e02SInna Palant makeNativeMethod("initHybrid", ConcreteTestHybrid::initHybrid),
225*65c59e02SInna Palant makeNativeMethod("concreteNum", ConcreteTestHybrid::concreteNum),
226*65c59e02SInna Palant });
227*65c59e02SInna Palant }
228*65c59e02SInna Palant
229*65c59e02SInna Palant private:
230*65c59e02SInna Palant friend HybridBase;
ConcreteTestHybrid(int nn,int cn)231*65c59e02SInna Palant ConcreteTestHybrid(int nn, int cn) : HybridBase(nn), concreteNum_(cn) {}
232*65c59e02SInna Palant
233*65c59e02SInna Palant int concreteNum_;
234*65c59e02SInna Palant };
235*65c59e02SInna Palant
cxxTestInheritance(alias_ref<jclass>,AbstractTestHybrid * ath)236*65c59e02SInna Palant static jboolean cxxTestInheritance(alias_ref<jclass>, AbstractTestHybrid* ath) {
237*65c59e02SInna Palant bool ret = true;
238*65c59e02SInna Palant
239*65c59e02SInna Palant ret &= ath->nativeNum() == 5;
240*65c59e02SInna Palant ret &= ath->sum() == 11;
241*65c59e02SInna Palant
242*65c59e02SInna Palant auto cth = dynamic_cast<ConcreteTestHybrid*>(ath);
243*65c59e02SInna Palant
244*65c59e02SInna Palant ret &= cth != nullptr;
245*65c59e02SInna Palant ret &= cth->concreteNum() == 6;
246*65c59e02SInna Palant
247*65c59e02SInna Palant return ret;
248*65c59e02SInna Palant }
249*65c59e02SInna Palant
makeAbstractHybrid(alias_ref<jclass>)250*65c59e02SInna Palant static local_ref<AbstractTestHybrid::jhybridobject> makeAbstractHybrid(
251*65c59e02SInna Palant alias_ref<jclass>) {
252*65c59e02SInna Palant auto cth = ConcreteTestHybrid::newObjectJavaArgs(0, 0, 0);
253*65c59e02SInna Palant weak_ref<ConcreteTestHybrid::jhybridobject> wcth = make_weak(cth);
254*65c59e02SInna Palant weak_ref<AbstractTestHybrid::jhybridobject> wath = wcth;
255*65c59e02SInna Palant
256*65c59e02SInna Palant local_ref<AbstractTestHybrid::jhybridobject> ath = cth;
257*65c59e02SInna Palant return ConcreteTestHybrid::newObjectJavaArgs(
258*65c59e02SInna Palant cthis(ath)->nativeNum() + 7, 8, 9);
259*65c59e02SInna Palant }
260*65c59e02SInna Palant
261*65c59e02SInna Palant struct Base : public JavaClass<Base> {
262*65c59e02SInna Palant static constexpr const char* const kJavaDescriptor =
263*65c59e02SInna Palant "Lcom/facebook/jni/HybridTests$Base;";
264*65c59e02SInna Palant };
265*65c59e02SInna Palant
266*65c59e02SInna Palant class Derived : public HybridClass<Derived, Base> {
267*65c59e02SInna Palant public:
268*65c59e02SInna Palant static constexpr const char* const kJavaDescriptor =
269*65c59e02SInna Palant "Lcom/facebook/jni/HybridTests$Derived;";
270*65c59e02SInna Palant
271*65c59e02SInna Palant private:
272*65c59e02SInna Palant friend HybridBase;
Derived()273*65c59e02SInna Palant Derived() {}
274*65c59e02SInna Palant };
275*65c59e02SInna Palant
276*65c59e02SInna Palant struct Destroyable : public HybridClass<Destroyable> {
277*65c59e02SInna Palant public:
278*65c59e02SInna Palant static constexpr const char* const kJavaDescriptor =
279*65c59e02SInna Palant "Lcom/facebook/jni/HybridTests$Destroyable;";
280*65c59e02SInna Palant
~DestroyableDestroyable281*65c59e02SInna Palant ~Destroyable() override {
282*65c59e02SInna Palant std::lock_guard<std::mutex> lk(*mtx_);
283*65c59e02SInna Palant *dead_ = true;
284*65c59e02SInna Palant cv_->notify_one();
285*65c59e02SInna Palant }
286*65c59e02SInna Palant
287*65c59e02SInna Palant using HybridBase::makeCxxInstance;
288*65c59e02SInna Palant
289*65c59e02SInna Palant private:
290*65c59e02SInna Palant friend HybridBase;
DestroyableDestroyable291*65c59e02SInna Palant Destroyable(
292*65c59e02SInna Palant std::shared_ptr<std::mutex> mtx,
293*65c59e02SInna Palant std::shared_ptr<bool> dead,
294*65c59e02SInna Palant std::shared_ptr<std::condition_variable> cv)
295*65c59e02SInna Palant : mtx_(mtx), dead_(dead), cv_(cv) {}
296*65c59e02SInna Palant
297*65c59e02SInna Palant std::shared_ptr<std::mutex> mtx_;
298*65c59e02SInna Palant std::shared_ptr<bool> dead_;
299*65c59e02SInna Palant std::shared_ptr<std::condition_variable> cv_;
300*65c59e02SInna Palant };
301*65c59e02SInna Palant
cxxTestHybridDestruction(alias_ref<jclass>)302*65c59e02SInna Palant static jboolean cxxTestHybridDestruction(alias_ref<jclass>) {
303*65c59e02SInna Palant auto mtx = std::make_shared<std::mutex>();
304*65c59e02SInna Palant auto dead = std::make_shared<bool>(false);
305*65c59e02SInna Palant auto cv = std::make_shared<std::condition_variable>();
306*65c59e02SInna Palant Destroyable::makeCxxInstance(mtx, dead, cv);
307*65c59e02SInna Palant std::unique_lock<std::mutex> lk(*mtx);
308*65c59e02SInna Palant cv->wait(lk, [&] { return dead; });
309*65c59e02SInna Palant return JNI_TRUE;
310*65c59e02SInna Palant }
311*65c59e02SInna Palant
cxxTestDerivedJavaClass(alias_ref<jclass>)312*65c59e02SInna Palant static jboolean cxxTestDerivedJavaClass(alias_ref<jclass>) {
313*65c59e02SInna Palant bool ret = true;
314*65c59e02SInna Palant
315*65c59e02SInna Palant auto derivedJava = Derived::newObjectCxxArgs();
316*65c59e02SInna Palant
317*65c59e02SInna Palant ret &= derivedJava ? true : false;
318*65c59e02SInna Palant ret &= derivedJava->isInstanceOf(Derived::javaClassLocal());
319*65c59e02SInna Palant ret &= derivedJava->isInstanceOf(Base::javaClassLocal());
320*65c59e02SInna Palant
321*65c59e02SInna Palant auto javaPtr = derivedJava.get();
322*65c59e02SInna Palant
323*65c59e02SInna Palant ret &= dynamic_cast<Derived::javaobject>(javaPtr) != nullptr;
324*65c59e02SInna Palant ret &= dynamic_cast<Base::javaobject>(javaPtr) != nullptr;
325*65c59e02SInna Palant ret &= dynamic_cast<jobject>(javaPtr) != nullptr;
326*65c59e02SInna Palant
327*65c59e02SInna Palant return ret;
328*65c59e02SInna Palant }
329*65c59e02SInna Palant
330*65c59e02SInna Palant class TestHybridClassBase
331*65c59e02SInna Palant : public facebook::jni::HybridClass<TestHybridClassBase> {
332*65c59e02SInna Palant public:
333*65c59e02SInna Palant static constexpr const char* const kJavaDescriptor =
334*65c59e02SInna Palant "Lcom/facebook/jni/HybridTests$TestHybridClassBase;";
335*65c59e02SInna Palant
TestHybridClassBase()336*65c59e02SInna Palant TestHybridClassBase() {}
337*65c59e02SInna Palant
TestHybridClassBase(int i)338*65c59e02SInna Palant explicit TestHybridClassBase(int i) : i_(i) {}
339*65c59e02SInna Palant
initHybrid(alias_ref<jhybridobject> o,jint i)340*65c59e02SInna Palant static void initHybrid(alias_ref<jhybridobject> o, jint i) {
341*65c59e02SInna Palant // The arguments will be forwarded to the ctor, and the result
342*65c59e02SInna Palant // will be saved in mHybridPointer in the java object.
343*65c59e02SInna Palant setCxxInstance(o, i);
344*65c59e02SInna Palant }
345*65c59e02SInna Palant
initHybrid2(alias_ref<jhybridobject> o)346*65c59e02SInna Palant static void initHybrid2(alias_ref<jhybridobject> o) {
347*65c59e02SInna Palant setCxxInstance(o);
348*65c59e02SInna Palant }
349*65c59e02SInna Palant
getInt()350*65c59e02SInna Palant virtual jint getInt() {
351*65c59e02SInna Palant return i_;
352*65c59e02SInna Palant }
353*65c59e02SInna Palant
setInt(int i)354*65c59e02SInna Palant void setInt(int i) {
355*65c59e02SInna Palant i_ = i;
356*65c59e02SInna Palant }
357*65c59e02SInna Palant
makeWithThree(alias_ref<jclass>)358*65c59e02SInna Palant static local_ref<jhybridobject> makeWithThree(
359*65c59e02SInna Palant alias_ref<jclass> /* unused */) {
360*65c59e02SInna Palant // The args are passed to C++ initialization directly.
361*65c59e02SInna Palant return newObjectCxxArgs(3);
362*65c59e02SInna Palant }
363*65c59e02SInna Palant
registerNatives()364*65c59e02SInna Palant static void registerNatives() {
365*65c59e02SInna Palant registerHybrid({
366*65c59e02SInna Palant makeNativeMethod("initHybrid", TestHybridClassBase::initHybrid),
367*65c59e02SInna Palant makeNativeMethod("initHybrid", TestHybridClassBase::initHybrid2),
368*65c59e02SInna Palant makeNativeMethod("getInt", TestHybridClassBase::getInt),
369*65c59e02SInna Palant makeNativeMethod("setInt", TestHybridClassBase::setInt),
370*65c59e02SInna Palant makeNativeMethod("makeWithThree", TestHybridClassBase::makeWithThree),
371*65c59e02SInna Palant });
372*65c59e02SInna Palant }
373*65c59e02SInna Palant
374*65c59e02SInna Palant private:
375*65c59e02SInna Palant int i_ = 0;
376*65c59e02SInna Palant };
377*65c59e02SInna Palant
RegisterTestHybridClass()378*65c59e02SInna Palant void RegisterTestHybridClass() {
379*65c59e02SInna Palant TestHybridClass::registerNatives();
380*65c59e02SInna Palant AbstractTestHybrid::registerNatives();
381*65c59e02SInna Palant ConcreteTestHybrid::registerNatives();
382*65c59e02SInna Palant TestHybridClassBase::registerNatives();
383*65c59e02SInna Palant
384*65c59e02SInna Palant registerNatives(
385*65c59e02SInna Palant "com/facebook/jni/HybridTests",
386*65c59e02SInna Palant {
387*65c59e02SInna Palant makeNativeMethod("cxxTestInheritance", cxxTestInheritance),
388*65c59e02SInna Palant makeNativeMethod("makeAbstractHybrid", makeAbstractHybrid),
389*65c59e02SInna Palant makeNativeMethod("cxxTestDerivedJavaClass", cxxTestDerivedJavaClass),
390*65c59e02SInna Palant makeNativeMethod(
391*65c59e02SInna Palant "cxxTestHybridDestruction", cxxTestHybridDestruction),
392*65c59e02SInna Palant });
393*65c59e02SInna Palant }
394