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 <cassert>
18*65c59e02SInna Palant #include <cstring>
19*65c59e02SInna Palant #include <stdexcept>
20*65c59e02SInna Palant #include <type_traits>
21*65c59e02SInna Palant #include <vector>
22*65c59e02SInna Palant
23*65c59e02SInna Palant // SECTION registration
24*65c59e02SInna Palant #include <fbjni/fbjni.h>
25*65c59e02SInna Palant using namespace facebook::jni;
26*65c59e02SInna Palant // END
27*65c59e02SInna Palant
28*65c59e02SInna Palant // SECTION byte_buffer
29*65c59e02SInna Palant #include <fbjni/ByteBuffer.h>
30*65c59e02SInna Palant // END
31*65c59e02SInna Palant
32*65c59e02SInna Palant // We can put all of our code in an anonymous namespace if
33*65c59e02SInna Palant // it is not used from any other C++ code.
34*65c59e02SInna Palant namespace {
35*65c59e02SInna Palant
36*65c59e02SInna Palant // SECTION inheritance
37*65c59e02SInna Palant struct JMyBaseClass : JavaClass<JMyBaseClass> {
38*65c59e02SInna Palant static constexpr auto kJavaDescriptor = "Lcom/facebook/jni/MyBaseClass;";
39*65c59e02SInna Palant };
40*65c59e02SInna Palant
41*65c59e02SInna Palant struct JMyDerivedClass : JavaClass<JMyDerivedClass, JMyBaseClass> {
42*65c59e02SInna Palant static constexpr auto kJavaDescriptor = "Lcom/facebook/jni/MyDerivedClass;";
43*65c59e02SInna Palant };
44*65c59e02SInna Palant
45*65c59e02SInna Palant /* MARKDOWN
46*65c59e02SInna Palant This will allow implicit casts from Derived to Base and explicit downcasts.
47*65c59e02SInna Palant When no base class is given, JObject will be used as the base.
48*65c59e02SInna Palant // END
49*65c59e02SInna Palant */
50*65c59e02SInna Palant
51*65c59e02SInna Palant // SECTION nested_class
52*65c59e02SInna Palant struct JNested : JavaClass<JNested> {
53*65c59e02SInna Palant static constexpr auto kJavaDescriptor = "Lcom/facebook/jni/Outer$Nested;";
create__anon99d09a770111::JNested54*65c59e02SInna Palant static local_ref<JNested> create() {
55*65c59e02SInna Palant return newInstance();
56*65c59e02SInna Palant }
57*65c59e02SInna Palant };
58*65c59e02SInna Palant // END
59*65c59e02SInna Palant
60*65c59e02SInna Palant // SECTION constructor
61*65c59e02SInna Palant struct JDataHolder : JavaClass<JDataHolder> {
62*65c59e02SInna Palant static constexpr auto kJavaDescriptor = "Lcom/facebook/jni/DataHolder;";
63*65c59e02SInna Palant // newInstance should be wrapped to ensure compile-time checking of call
64*65c59e02SInna Palant // sites.
create__anon99d09a770111::JDataHolder65*65c59e02SInna Palant static local_ref<JDataHolder> create(int i, std::string const& s) {
66*65c59e02SInna Palant // Constructor is looked up by argument types at *runtime*.
67*65c59e02SInna Palant return newInstance(i, s);
68*65c59e02SInna Palant }
69*65c59e02SInna Palant // END
70*65c59e02SInna Palant
71*65c59e02SInna Palant // SECTION fields
getAndSetFields__anon99d09a770111::JDataHolder72*65c59e02SInna Palant void getAndSetFields() {
73*65c59e02SInna Palant static const auto cls = javaClassStatic();
74*65c59e02SInna Palant // Primitive fields.
75*65c59e02SInna Palant static const auto iField = cls->getField<jint>("i");
76*65c59e02SInna Palant jint i = this->getFieldValue(iField);
77*65c59e02SInna Palant this->setFieldValue(iField, i + 1);
78*65c59e02SInna Palant // Object fields work for standard classes and your own JavaObject classes.
79*65c59e02SInna Palant static const auto sField = cls->getField<JString>("s");
80*65c59e02SInna Palant // Object are returned as local refs ...
81*65c59e02SInna Palant local_ref<JString> s = this->getFieldValue(sField);
82*65c59e02SInna Palant // and can be set from any ref.
83*65c59e02SInna Palant this->setFieldValue(sField, make_jstring(s->toStdString() + "1").get());
84*65c59e02SInna Palant // Static fields work the same, but getStaticField, getStaticFieldValue,
85*65c59e02SInna Palant // and setStaticFieldValue must all be called on the class object.
86*65c59e02SInna Palant static const auto someInstanceField =
87*65c59e02SInna Palant cls->getStaticField<JDataHolder>("someInstance");
88*65c59e02SInna Palant auto inst = cls->getStaticFieldValue(someInstanceField);
89*65c59e02SInna Palant if (!inst) {
90*65c59e02SInna Palant // NOTE: Can't use cls here because it is declared const.
91*65c59e02SInna Palant getClass()->setStaticFieldValue(someInstanceField, self());
92*65c59e02SInna Palant }
93*65c59e02SInna Palant }
94*65c59e02SInna Palant // END
95*65c59e02SInna Palant
getStr__anon99d09a770111::JDataHolder96*65c59e02SInna Palant local_ref<JString> getStr() {
97*65c59e02SInna Palant static const auto cls = javaClassStatic();
98*65c59e02SInna Palant static const auto sField = cls->getField<JString>("s");
99*65c59e02SInna Palant return getFieldValue(sField);
100*65c59e02SInna Palant }
101*65c59e02SInna Palant };
102*65c59e02SInna Palant
103*65c59e02SInna Palant // SECTION registration
104*65c59e02SInna Palant // Standard declaration for a normal class (no C++ fields).
105*65c59e02SInna Palant struct DocTests : JavaClass<DocTests> {
106*65c59e02SInna Palant static constexpr auto kJavaDescriptor = "Lcom/facebook/jni/DocTests;";
107*65c59e02SInna Palant // END
108*65c59e02SInna Palant
109*65c59e02SInna Palant // SECTION constructor
110*65c59e02SInna Palant // Call-site in another file.
runConstructor__anon99d09a770111::DocTests111*65c59e02SInna Palant static local_ref<JDataHolder> runConstructor(alias_ref<JClass> clazz) {
112*65c59e02SInna Palant // Call to ordinatry C++ function is checked at *compile time*.
113*65c59e02SInna Palant return JDataHolder::create(1, "hi");
114*65c59e02SInna Palant }
115*65c59e02SInna Palant // END
116*65c59e02SInna Palant
117*65c59e02SInna Palant // SECTION basic_methods
118*65c59e02SInna Palant public:
119*65c59e02SInna Palant // Java methods should usually be wrapped by C++ methods for ease-of-use.
120*65c59e02SInna Palant // (Most other examples in this document will inline these for brevity.)
callVoidMethod__anon99d09a770111::DocTests121*65c59e02SInna Palant void callVoidMethod() {
122*65c59e02SInna Palant static const auto method = getClass()->getMethod<void()>("voidMethod");
123*65c59e02SInna Palant // self() returns the raw JNI reference to this object.
124*65c59e02SInna Palant method(self());
125*65c59e02SInna Palant }
callStaticVoidMethod__anon99d09a770111::DocTests126*65c59e02SInna Palant static void callStaticVoidMethod() {
127*65c59e02SInna Palant static const auto cls = javaClassStatic();
128*65c59e02SInna Palant static const auto method = cls->getStaticMethod<void()>("staticVoidMethod");
129*65c59e02SInna Palant method(cls);
130*65c59e02SInna Palant }
131*65c59e02SInna Palant
132*65c59e02SInna Palant // Native implementations of Java methods can be private.
133*65c59e02SInna Palant private:
134*65c59e02SInna Palant // For non-Hybrid objects, all JNI methods must be static on the C++ side
135*65c59e02SInna Palant // because only Hybrid objects can have C++ state.
nativeVoidMethod__anon99d09a770111::DocTests136*65c59e02SInna Palant static void nativeVoidMethod(
137*65c59e02SInna Palant // All non-static methods receive "this" as a first argument.
138*65c59e02SInna Palant alias_ref<DocTests> thiz) {
139*65c59e02SInna Palant // Make sure we got the right object.
140*65c59e02SInna Palant assert(thiz->toString() == "instance of DocTests");
141*65c59e02SInna Palant thiz->callVoidMethod();
142*65c59e02SInna Palant }
staticNativeVoidMethod__anon99d09a770111::DocTests143*65c59e02SInna Palant static void staticNativeVoidMethod(
144*65c59e02SInna Palant // All static methods receive the class as a first argument.
145*65c59e02SInna Palant alias_ref<JClass> clazz) {
146*65c59e02SInna Palant assert(clazz->toString() == "class com.facebook.jni.DocTests");
147*65c59e02SInna Palant DocTests::callStaticVoidMethod();
148*65c59e02SInna Palant }
149*65c59e02SInna Palant // END
150*65c59e02SInna Palant
151*65c59e02SInna Palant // SECTION primitives
152*65c59e02SInna Palant static jlong
addSomeNumbers__anon99d09a770111::DocTests153*65c59e02SInna Palant addSomeNumbers(alias_ref<JClass> clazz, jbyte b, jshort s, jint i) {
154*65c59e02SInna Palant static const auto doubler = clazz->getStaticMethod<jlong(jint)>("doubler");
155*65c59e02SInna Palant jlong l = doubler(clazz, 4);
156*65c59e02SInna Palant return b + s + i + l;
157*65c59e02SInna Palant }
158*65c59e02SInna Palant
159*65c59e02SInna Palant /* MARKDOWN
160*65c59e02SInna Palant Argument and return types can be in either JNI style or C++ style.
161*65c59e02SInna Palant
162*65c59e02SInna Palant | Java type | JNI types |
163*65c59e02SInna Palant | --- | --- |
164*65c59e02SInna Palant | `boolean` | `jboolean`, `bool` |
165*65c59e02SInna Palant | `byte` | `jbyte`, `int8_t` |
166*65c59e02SInna Palant | `char` | `jchar` |
167*65c59e02SInna Palant | `short` | `jshort`, `short`, `int16_t` |
168*65c59e02SInna Palant | `int` | `jint`, `int`, `int32_t` |
169*65c59e02SInna Palant | `long` | `jlong`, `int64_t` |
170*65c59e02SInna Palant | `float` | `jfloat`, `float` |
171*65c59e02SInna Palant | `double` | `jdouble`, `double` |
172*65c59e02SInna Palant // END
173*65c59e02SInna Palant */
174*65c59e02SInna Palant
175*65c59e02SInna Palant // SECTION strings
fancyCat__anon99d09a770111::DocTests176*65c59e02SInna Palant static std::string fancyCat(
177*65c59e02SInna Palant alias_ref<JClass> clazz,
178*65c59e02SInna Palant // Native methods can receive strings as JString (direct JNI reference)
179*65c59e02SInna Palant // ...
180*65c59e02SInna Palant alias_ref<JString> s1,
181*65c59e02SInna Palant // or as std::string (converted to real UTF-8).
182*65c59e02SInna Palant std::string s2) {
183*65c59e02SInna Palant // Convert JString to std::string.
184*65c59e02SInna Palant std::string result = s1->toStdString();
185*65c59e02SInna Palant // Java methods can receive and return JString ...
186*65c59e02SInna Palant static const auto doubler_java =
187*65c59e02SInna Palant clazz->getStaticMethod<JString(JString)>("doubler");
188*65c59e02SInna Palant result += doubler_java(clazz, *s1)->toStdString();
189*65c59e02SInna Palant // and also std::string (converted from real UTF-8).
190*65c59e02SInna Palant static const auto doubler_std =
191*65c59e02SInna Palant clazz->getStaticMethod<std::string(std::string)>("doubler");
192*65c59e02SInna Palant result += doubler_std(clazz, s2)->toStdString();
193*65c59e02SInna Palant // They can also receive const char*, but not return it.
194*65c59e02SInna Palant static const auto doubler_char =
195*65c59e02SInna Palant clazz->getStaticMethod<std::string(const char*)>("doubler");
196*65c59e02SInna Palant result += doubler_char(clazz, s2.c_str())->toStdString();
197*65c59e02SInna Palant // All 3 formats can be returned (std::string shown here, const char*
198*65c59e02SInna Palant // below).
199*65c59e02SInna Palant return result;
200*65c59e02SInna Palant }
201*65c59e02SInna Palant
getCString__anon99d09a770111::DocTests202*65c59e02SInna Palant static const char* getCString(alias_ref<JClass>) {
203*65c59e02SInna Palant // This string is converted to JString *after* getCString returns.
204*65c59e02SInna Palant // Watch your memory lifetimes.
205*65c59e02SInna Palant return "Watch your memory.";
206*65c59e02SInna Palant }
207*65c59e02SInna Palant // END
208*65c59e02SInna Palant
209*65c59e02SInna Palant // SECTION primitive_arrays
primitiveArrays__anon99d09a770111::DocTests210*65c59e02SInna Palant static local_ref<JArrayInt> primitiveArrays(
211*65c59e02SInna Palant alias_ref<JClass> clazz,
212*65c59e02SInna Palant // JArrayX is available for all primitives.
213*65c59e02SInna Palant alias_ref<JArrayInt> arr) {
214*65c59e02SInna Palant size_t size = arr->size();
215*65c59e02SInna Palant std::vector<jint> buffer(size + 1L);
216*65c59e02SInna Palant // Copy elements into native memory.
217*65c59e02SInna Palant arr->getRegion(0, size, buffer.data());
218*65c59e02SInna Palant // Copy elements into fresh memory (returns unique_ptr<int[]>).
219*65c59e02SInna Palant auto elements = arr->getRegion(0, size);
220*65c59e02SInna Palant // Pin can eliminate the need for a copy.
221*65c59e02SInna Palant {
222*65c59e02SInna Palant auto pin = arr->pin();
223*65c59e02SInna Palant for (size_t i = 0; i < pin.size(); i++) {
224*65c59e02SInna Palant // Can read and/or write pin[i].
225*65c59e02SInna Palant buffer[size] += pin[i];
226*65c59e02SInna Palant }
227*65c59e02SInna Palant }
228*65c59e02SInna Palant // Allocating a new array and copying data in.
229*65c59e02SInna Palant // (Data can also be assigned by writing to a pin.)
230*65c59e02SInna Palant auto ret = JArrayInt::newArray(size + 1);
231*65c59e02SInna Palant ret->setRegion(0, size + 1, buffer.data());
232*65c59e02SInna Palant return ret;
233*65c59e02SInna Palant }
234*65c59e02SInna Palant // END
235*65c59e02SInna Palant
236*65c59e02SInna Palant // SECTION class_arrays
classArrays__anon99d09a770111::DocTests237*65c59e02SInna Palant static local_ref<JArrayClass<JString>> classArrays(
238*65c59e02SInna Palant alias_ref<JClass> clazz,
239*65c59e02SInna Palant alias_ref<JArrayClass<JDataHolder>> arr) {
240*65c59e02SInna Palant size_t size = arr->size();
241*65c59e02SInna Palant local_ref<JArrayClass<JString>> ret = JArrayClass<JString>::newArray(size);
242*65c59e02SInna Palant for (int i = 0; i < size; ++i) {
243*65c59e02SInna Palant local_ref<JString> str = arr->getElement(i)->getStr();
244*65c59e02SInna Palant ret->setElement(i, *str);
245*65c59e02SInna Palant }
246*65c59e02SInna Palant return ret;
247*65c59e02SInna Palant }
248*65c59e02SInna Palant // END
249*65c59e02SInna Palant
250*65c59e02SInna Palant // SECTION references
251*65c59e02SInna Palant /* MARKDOWN
252*65c59e02SInna Palant
253*65c59e02SInna Palant ### `alias_ref<JFoo>`
254*65c59e02SInna Palant `alias_ref` is a non-owning reference, like a bare pointer.
255*65c59e02SInna Palant It is used almost exclusively for function arguments.
256*65c59e02SInna Palant
257*65c59e02SInna Palant ### `local_ref<JFoo>`
258*65c59e02SInna Palant `local_ref` is a ref-counted thread-specific pointer that is invalidated upon
259*65c59e02SInna Palant returning to Java. For variables used within a function, use `local_ref`. Most
260*65c59e02SInna Palant functions should return `local_ref` (and let the caller convert to a
261*65c59e02SInna Palant `global_ref` if necessary).
262*65c59e02SInna Palant
263*65c59e02SInna Palant ### `global_ref<JFoo>`
264*65c59e02SInna Palant `global_ref` is a ref-counted pointer.
265*65c59e02SInna Palant Use this for storing a reference to a Java object that may
266*65c59e02SInna Palant outlive the current call from Java into C++
267*65c59e02SInna Palant (e.g. class member fields are usually global refs).
268*65c59e02SInna Palant You can create a new `global_ref` (from an `alias_ref`/`local_ref`) by calling
269*65c59e02SInna Palant `make_global`.
270*65c59e02SInna Palant // END
271*65c59e02SInna Palant */
272*65c59e02SInna Palant // SECTION references
convertReferences__anon99d09a770111::DocTests273*65c59e02SInna Palant static local_ref<JObject> convertReferences(
274*65c59e02SInna Palant alias_ref<JClass> clazz,
275*65c59e02SInna Palant alias_ref<JMyDerivedClass> derived) {
276*65c59e02SInna Palant local_ref<JMyDerivedClass> local_derived = make_local(derived);
277*65c59e02SInna Palant global_ref<JMyDerivedClass> global_derived = make_global(derived);
278*65c59e02SInna Palant // Store global_derived somewhere.
279*65c59e02SInna Palant return local_derived;
280*65c59e02SInna Palant }
281*65c59e02SInna Palant // END
282*65c59e02SInna Palant
283*65c59e02SInna Palant // SECTION inheritance
castReferences__anon99d09a770111::DocTests284*65c59e02SInna Palant static void castReferences(
285*65c59e02SInna Palant alias_ref<JClass> clazz,
286*65c59e02SInna Palant alias_ref<JMyBaseClass> base) {
287*65c59e02SInna Palant // Just like raw pointers, upcasting is implicit.
288*65c59e02SInna Palant alias_ref<JObject> obj = base;
289*65c59e02SInna Palant // static_ref_cast is like C++ static_cast. No runtime checking is done.
290*65c59e02SInna Palant alias_ref<JMyDerivedClass> derived_1 =
291*65c59e02SInna Palant static_ref_cast<JMyDerivedClass>(base);
292*65c59e02SInna Palant // dynamic_ref_cast is like C++ dynamic_cast.
293*65c59e02SInna Palant // It will check that the runtime Java type is actually derived from the
294*65c59e02SInna Palant // target type.
295*65c59e02SInna Palant try {
296*65c59e02SInna Palant alias_ref<JMyDerivedClass> derived_2 =
297*65c59e02SInna Palant dynamic_ref_cast<JMyDerivedClass>(base);
298*65c59e02SInna Palant (void)derived_2;
299*65c59e02SInna Palant } catch (const JniException& exn) {
300*65c59e02SInna Palant // Throws ClassCastException if the cast fails.
301*65c59e02SInna Palant throw;
302*65c59e02SInna Palant }
303*65c59e02SInna Palant // END
304*65c59e02SInna Palant // Supress warnings.
305*65c59e02SInna Palant (void)obj;
306*65c59e02SInna Palant (void)derived_1;
307*65c59e02SInna Palant }
308*65c59e02SInna Palant
callGetAndSetFields__anon99d09a770111::DocTests309*65c59e02SInna Palant static void callGetAndSetFields(
310*65c59e02SInna Palant alias_ref<JClass> clazz,
311*65c59e02SInna Palant alias_ref<JDataHolder> data) {
312*65c59e02SInna Palant data->getAndSetFields();
313*65c59e02SInna Palant }
314*65c59e02SInna Palant
315*65c59e02SInna Palant // SECTION jobject_jclass
showJObject__anon99d09a770111::DocTests316*65c59e02SInna Palant static std::string showJObject(
317*65c59e02SInna Palant alias_ref<JClass> clazz,
318*65c59e02SInna Palant // JObject is the base class of all fbjni types. It corresponds to
319*65c59e02SInna Palant // java.lang.Object.
320*65c59e02SInna Palant alias_ref<JObject> obj,
321*65c59e02SInna Palant alias_ref<JDataHolder> data) {
322*65c59e02SInna Palant local_ref<JClass> objClass = obj->getClass();
323*65c59e02SInna Palant local_ref<JClass> dataClass = data->getClass();
324*65c59e02SInna Palant local_ref<JClass> parent = dataClass->getSuperclass();
325*65c59e02SInna Palant assert(isSameObject(parent, objClass));
326*65c59e02SInna Palant assert(data->isInstanceOf(parent));
327*65c59e02SInna Palant assert(objClass->isAssignableFrom(clazz));
328*65c59e02SInna Palant std::string str = "data=";
329*65c59e02SInna Palant {
330*65c59e02SInna Palant // Acquires the object lock until this object goes out of scope.
331*65c59e02SInna Palant auto lock = data->lock();
332*65c59e02SInna Palant // Calls Object.toString and converts to std::string.
333*65c59e02SInna Palant str += data->toString();
334*65c59e02SInna Palant }
335*65c59e02SInna Palant // All JavaClass types have a `javaobject` typedef, which is their raw JNI
336*65c59e02SInna Palant // type.
337*65c59e02SInna Palant static_assert(std::is_same<JObject::javaobject, jobject>::value, "");
338*65c59e02SInna Palant static_assert(std::is_same<JClass::javaobject, jclass>::value, "");
339*65c59e02SInna Palant static_assert(!std::is_same<JDataHolder::javaobject, jobject>::value, "");
340*65c59e02SInna Palant static_assert(
341*65c59e02SInna Palant std::is_convertible<JDataHolder::javaobject, jobject>::value, "");
342*65c59e02SInna Palant return str;
343*65c59e02SInna Palant }
344*65c59e02SInna Palant // END
345*65c59e02SInna Palant
346*65c59e02SInna Palant // SECTION simple_exceptions
catchAndThrow__anon99d09a770111::DocTests347*65c59e02SInna Palant static void catchAndThrow(alias_ref<JClass> clazz) {
348*65c59e02SInna Palant try {
349*65c59e02SInna Palant clazz->getStaticMethod<void()>("doesNotExist");
350*65c59e02SInna Palant assert(!"Exception wasn't thrown.");
351*65c59e02SInna Palant } catch (JniException& exn) {
352*65c59e02SInna Palant // JniException extends std::exception, so "catch (std::exception& exn)"
353*65c59e02SInna Palant // also works.
354*65c59e02SInna Palant local_ref<JThrowable> underlying = exn.getThrowable();
355*65c59e02SInna Palant const char* msg = exn.what();
356*65c59e02SInna Palant // Throwing exceptions from C++ is fine.
357*65c59e02SInna Palant // They will be translated to an appropriate Java exception type.
358*65c59e02SInna Palant throw std::runtime_error(std::string() + "Caught '" + msg + "'");
359*65c59e02SInna Palant }
360*65c59e02SInna Palant }
361*65c59e02SInna Palant // END
362*65c59e02SInna Palant
363*65c59e02SInna Palant // SECTION boxed
scaleUp__anon99d09a770111::DocTests364*65c59e02SInna Palant static local_ref<JDouble> scaleUp(
365*65c59e02SInna Palant alias_ref<JClass> clazz,
366*65c59e02SInna Palant alias_ref<JInteger> number) {
367*65c59e02SInna Palant // Boxed types exist for all Java primitive types.
368*65c59e02SInna Palant // Unbox with ->value() or ->intValue.
369*65c59e02SInna Palant jint unboxed = number->value();
370*65c59e02SInna Palant jdouble scaled = unboxed * 1.5;
371*65c59e02SInna Palant // Box with autobox() or JDouble::valueOf.
372*65c59e02SInna Palant local_ref<JDouble> ret = autobox(scaled);
373*65c59e02SInna Palant return ret;
374*65c59e02SInna Palant }
375*65c59e02SInna Palant // END
376*65c59e02SInna Palant
377*65c59e02SInna Palant // SECTION iterables
concatMatches__anon99d09a770111::DocTests378*65c59e02SInna Palant static std::string concatMatches(
379*65c59e02SInna Palant alias_ref<JClass> clazz,
380*65c59e02SInna Palant // Note that generic types are *not* checked against Java declarations.
381*65c59e02SInna Palant alias_ref<JList<JInteger>> values,
382*65c59e02SInna Palant alias_ref<JMap<JString, JInteger>> names) {
383*65c59e02SInna Palant int sum = 0;
384*65c59e02SInna Palant std::string ret;
385*65c59e02SInna Palant // Iterator and Iterable support C++ iteration.
386*65c59e02SInna Palant // Collection, List, and Set support iteration and ->size().
387*65c59e02SInna Palant for (const auto& elem : *values) {
388*65c59e02SInna Palant sum += elem->value();
389*65c59e02SInna Palant }
390*65c59e02SInna Palant // Maps iterate like C++ maps.
391*65c59e02SInna Palant for (const auto& entry : *names) {
392*65c59e02SInna Palant if (entry.second->value() == sum) {
393*65c59e02SInna Palant ret += entry.first->toStdString();
394*65c59e02SInna Palant }
395*65c59e02SInna Palant }
396*65c59e02SInna Palant // This works if you build with C++17.
397*65c59e02SInna Palant // for (const auto& [key, value] : *names) {
398*65c59e02SInna Palant return ret;
399*65c59e02SInna Palant }
400*65c59e02SInna Palant // END
401*65c59e02SInna Palant
402*65c59e02SInna Palant // SECTION collections
buildCollections__anon99d09a770111::DocTests403*65c59e02SInna Palant static local_ref<JMap<JString, JList<JInteger>>> buildCollections(
404*65c59e02SInna Palant alias_ref<JClass> clazz) {
405*65c59e02SInna Palant auto primes = JArrayList<JInteger>::create();
406*65c59e02SInna Palant primes->add(autobox(2));
407*65c59e02SInna Palant primes->add(autobox(3));
408*65c59e02SInna Palant auto wrapper = JHashMap<JString, JList<JInteger>>::create();
409*65c59e02SInna Palant wrapper->put(make_jstring("primes"), primes);
410*65c59e02SInna Palant return wrapper;
411*65c59e02SInna Palant }
412*65c59e02SInna Palant // END
413*65c59e02SInna Palant
414*65c59e02SInna Palant // SECTION byte_buffer
transformBuffer__anon99d09a770111::DocTests415*65c59e02SInna Palant static local_ref<JByteBuffer> transformBuffer(
416*65c59e02SInna Palant alias_ref<JClass> clazz,
417*65c59e02SInna Palant alias_ref<JByteBuffer> data) {
418*65c59e02SInna Palant // Direct ByteBuffers are an efficient way to transfer bulk data between
419*65c59e02SInna Palant // Java and C++.
420*65c59e02SInna Palant if (!data->isDirect()) {
421*65c59e02SInna Palant throw std::runtime_error("Argument is not a direct buffer.");
422*65c59e02SInna Palant }
423*65c59e02SInna Palant // Transform data into a local buffer.
424*65c59e02SInna Palant std::vector<uint8_t> buffer(data->getDirectSize());
425*65c59e02SInna Palant uint8_t* raw_data = data->getDirectBytes();
426*65c59e02SInna Palant for (size_t i = 0; i < buffer.size(); ++i) {
427*65c59e02SInna Palant buffer[i] = raw_data[i] + 1;
428*65c59e02SInna Palant }
429*65c59e02SInna Palant // Wrap our data in a buffer and pass to Java.
430*65c59e02SInna Palant // Note that the buffer *directly* references our memory.
431*65c59e02SInna Palant local_ref<JByteBuffer> wrapper =
432*65c59e02SInna Palant JByteBuffer::wrapBytes(buffer.data(), buffer.size());
433*65c59e02SInna Palant static const auto receiver =
434*65c59e02SInna Palant clazz->getStaticMethod<void(alias_ref<JByteBuffer>)>("receiveBuffer");
435*65c59e02SInna Palant receiver(clazz, wrapper);
436*65c59e02SInna Palant // We can create a new buffer that owns its own memory and safely return it.
437*65c59e02SInna Palant local_ref<JByteBuffer> ret = JByteBuffer::allocateDirect(buffer.size());
438*65c59e02SInna Palant std::memcpy(ret->getDirectBytes(), buffer.data(), buffer.size());
439*65c59e02SInna Palant return ret;
440*65c59e02SInna Palant }
441*65c59e02SInna Palant // END
442*65c59e02SInna Palant
443*65c59e02SInna Palant public:
444*65c59e02SInna Palant // SECTION registration
445*65c59e02SInna Palant // NOTE: The name of this method doesn't matter.
registerNatives__anon99d09a770111::DocTests446*65c59e02SInna Palant static void registerNatives() {
447*65c59e02SInna Palant javaClassStatic()->registerNatives({
448*65c59e02SInna Palant makeNativeMethod("nativeVoidMethod", DocTests::nativeVoidMethod),
449*65c59e02SInna Palant makeNativeMethod(
450*65c59e02SInna Palant "staticNativeVoidMethod", DocTests::staticNativeVoidMethod),
451*65c59e02SInna Palant // END
452*65c59e02SInna Palant makeNativeMethod("addSomeNumbers", DocTests::addSomeNumbers),
453*65c59e02SInna Palant makeNativeMethod("fancyCat", DocTests::fancyCat),
454*65c59e02SInna Palant makeNativeMethod("getCString", DocTests::getCString),
455*65c59e02SInna Palant makeNativeMethod("primitiveArrays", DocTests::primitiveArrays),
456*65c59e02SInna Palant makeNativeMethod("convertReferences", DocTests::convertReferences),
457*65c59e02SInna Palant makeNativeMethod("castReferences", DocTests::castReferences),
458*65c59e02SInna Palant makeNativeMethod("runConstructor", DocTests::runConstructor),
459*65c59e02SInna Palant makeNativeMethod("callGetAndSetFields", DocTests::callGetAndSetFields),
460*65c59e02SInna Palant makeNativeMethod("showJObject", DocTests::showJObject),
461*65c59e02SInna Palant makeNativeMethod("catchAndThrow", DocTests::catchAndThrow),
462*65c59e02SInna Palant makeNativeMethod("scaleUp", DocTests::scaleUp),
463*65c59e02SInna Palant makeNativeMethod("concatMatches", DocTests::concatMatches),
464*65c59e02SInna Palant makeNativeMethod("buildCollections", DocTests::buildCollections),
465*65c59e02SInna Palant makeNativeMethod("transformBuffer", DocTests::transformBuffer),
466*65c59e02SInna Palant });
467*65c59e02SInna Palant }
468*65c59e02SInna Palant };
469*65c59e02SInna Palant
470*65c59e02SInna Palant } // Anonymous namespace
471*65c59e02SInna Palant
472*65c59e02SInna Palant // SECTION registration
JNI_OnLoad(JavaVM * vm,void *)473*65c59e02SInna Palant jint JNI_OnLoad(JavaVM* vm, void*) {
474*65c59e02SInna Palant return facebook::jni::initialize(vm, [] { DocTests::registerNatives(); });
475*65c59e02SInna Palant }
476*65c59e02SInna Palant // END
477