xref: /aosp_15_r20/external/fbjni/cxx/fbjni/detail/CoreClasses.h (revision 65c59e023c5336bbd4a23be7af78407e3d80e7e7)
1 /*
2  * Copyright (c) Facebook, Inc. and its affiliates.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #pragma once
18 
19 /** @file CoreClasses.h
20  *
21  * In CoreClasses.h wrappers for the core classes (jobject, jclass, and jstring)
22  * is defined to provide access to corresponding JNI functions + some
23  * conveniance.
24  */
25 
26 #include "Meta-forward.h"
27 #include "References-forward.h"
28 #include "TypeTraits.h"
29 
30 #include <memory>
31 
32 #include <jni.h>
33 
34 #include <fbjni/detail/SimpleFixedString.h>
35 
36 namespace facebook {
37 namespace jni {
38 
39 class JClass;
40 class JObject;
41 class JString;
42 
43 namespace detail {
44 
45 /// Lookup a class by name.  This should only be used internally.
46 jclass findClass(JNIEnv* env, const char* name);
47 
48 } // namespace detail
49 
50 /// Lookup a class by name. Note this functions returns an alias_ref that
51 /// points to a leaked global reference.  This is appropriate for classes
52 /// that are never unloaded (which is any class in an Android app and most
53 /// Java programs).
54 ///
55 /// The most common use case for this is storing the result
56 /// in a "static auto" variable, or a static global.
57 ///
58 /// @return Returns a leaked global reference to the class
59 alias_ref<JClass> findClassStatic(const char* name);
60 
61 /// Lookup a class by name. Note this functions returns a local reference,
62 /// which means that it must not be stored in a static variable.
63 ///
64 /// The most common use case for this is one-time initialization
65 /// (like caching method ids).
66 ///
67 /// @return Returns a global reference to the class
68 local_ref<JClass> findClassLocal(const char* name);
69 
70 /// Check to see if two references refer to the same object. Comparison with
71 /// nullptr returns true if and only if compared to another nullptr. A weak
72 /// reference that refers to a reclaimed object count as nullptr.
73 bool isSameObject(alias_ref<JObject> lhs, alias_ref<JObject> rhs) noexcept;
74 
75 // Together, these classes allow convenient use of any class with the fbjni
76 // helpers.  To use:
77 //
78 // struct MyClass : public JavaClass<MyClass> {
79 //   constexpr static auto kJavaDescriptor = "Lcom/example/package/MyClass;";
80 // };
81 //
82 // Then, an alias_ref<MyClass> will be backed by an instance of MyClass.
83 // JavaClass provides a convenient way to add functionality to these
84 // smart references.
85 //
86 // For example:
87 //
88 // struct MyClass : public JavaClass<MyClass> {
89 //   constexpr static auto kJavaDescriptor = "Lcom/example/package/MyClass;";
90 //
91 //   void foo() {
92 //     static const auto method = javaClassStatic()->getMethod<void()>("foo");
93 //     method(self());
94 //   }
95 //
96 //   static local_ref<javaobject> create(int i) {
97 //     return newInstance(i);
98 //   }
99 // };
100 //
101 // auto obj = MyClass::create(10);
102 // obj->foo();
103 //
104 // While users of a JavaClass-type can lookup methods and fields through the
105 // underlying JClass, those calls can only be checked at runtime. It is
106 // recommended that the JavaClass-type instead explicitly expose it's methods as
107 // in the example above.
108 
109 namespace detail {
110 template <typename JC, typename... Args>
111 static local_ref<JC> newInstance(Args... args);
112 }
113 
114 class MonitorLock;
115 
116 class JObject : detail::JObjectBase {
117  public:
118   static constexpr auto kJavaDescriptor = "Ljava/lang/Object;";
119 
120   static constexpr detail::SimpleFixedString<0>
get_instantiated_java_descriptor()121   get_instantiated_java_descriptor() {
122     return "";
123   }
get_instantiated_base_name()124   static constexpr detail::SimpleFixedString<0> get_instantiated_base_name() {
125     return "";
126   }
127 
128   /// Get a @ref local_ref of the object's class
129   local_ref<JClass> getClass() const noexcept;
130 
131   /// Checks if the object is an instance of a class
132   bool isInstanceOf(alias_ref<JClass> cls) const noexcept;
133 
134   /// Get the primitive value of a field
135   template <typename T>
136   T getFieldValue(JField<T> field) const noexcept;
137 
138   /// Get and wrap the value of a field in a @ref local_ref
139   template <typename T>
140   local_ref<T*> getFieldValue(JField<T*> field) const noexcept;
141 
142   /// Set the value of field. Any Java type is accepted.
143   template <typename T>
144   void setFieldValue(JField<T> field, T value) noexcept;
145   template <
146       typename T,
147       typename = typename std::enable_if<IsPlainJniReference<T>(), T>::type>
148   void setFieldValue(JField<T> field, alias_ref<T> value) noexcept;
149 
150   /// Convenience method to create a std::string representing the object
151   std::string toString() const;
152 
153   // Take this object's monitor lock
154   MonitorLock lock() const noexcept;
155 
156   typedef _jobject _javaobject;
157   typedef _javaobject* javaobject;
158 
159  protected:
160   jobject self() const noexcept;
161 
162  private:
163   friend void swap(JObject& a, JObject& b) noexcept;
164   template <typename>
165   friend struct detail::ReprAccess;
166   template <typename, typename, typename>
167   friend class JavaClass;
168 };
169 
170 namespace detail {
171 template <typename, typename Base, typename JType>
172 struct JTypeFor {
173   static_assert(
174       std::is_base_of<
175           std::remove_pointer<jobject>::type,
176           typename std::remove_pointer<JType>::type>::value,
177       "");
178   using _javaobject = typename std::remove_pointer<JType>::type;
179   using javaobject = JType;
180 };
181 
182 template <typename T, typename Base>
183 struct JTypeFor<T, Base, void> {
184   // JNI pattern for jobject assignable pointer
185   struct _javaobject : Base::_javaobject {
186     // This allows us to map back to the defining type (in ReprType, for
187     // example).
188     typedef T JniRefRepr;
189   };
190   using javaobject = _javaobject*;
191 };
192 } // namespace detail
193 
194 // JavaClass provides a method to inform fbjni about user-defined Java types.
195 // Given a class:
196 // struct Foo : JavaClass<Foo> {
197 //   static constexpr auto kJavaDescriptor = "Lcom/example/package/Foo;";
198 // };
199 // fbjni can determine the java type/method signatures for Foo::javaobject and
200 // smart refs (like alias_ref<Foo>) will hold an instance of Foo
201 // and provide access to it through the -> and * operators.
202 //
203 // The "Base" template argument can be used to specify the JavaClass superclass
204 // of this type (for instance, JString's Base is JObject).
205 //
206 // The "JType" template argument is used to provide a jni type (like jstring,
207 // jthrowable) to be used as javaobject. This should only be necessary for
208 // built-in jni types and not user-defined ones.
209 template <typename T, typename Base = JObject, typename JType = void>
210 class JavaClass : public Base {
211   using JObjType = typename detail::JTypeFor<T, Base, JType>;
212 
213  public:
214   using _javaobject = typename JObjType::_javaobject;
215   using javaobject = typename JObjType::javaobject;
216 
217   using JavaBase = JavaClass;
218 
219   static alias_ref<JClass> javaClassStatic();
220   static local_ref<JClass> javaClassLocal();
221 
222  protected:
223   /// Allocates a new object and invokes the specified constructor
224   /// Like JClass's getConstructor, this function can only check at runtime if
225   /// the class actually has a constructor that accepts the corresponding types.
226   /// While a JavaClass-type can expose this function directly, it is
227   /// recommended to instead to use this to explicitly only expose those
228   /// constructors that the Java class actually has (i.e. with static create()
229   /// functions).
230   template <typename... Args>
231   static local_ref<T> newInstance(Args... args) {
232     return detail::newInstance<T>(args...);
233   }
234 
235   javaobject self() const noexcept;
236 };
237 
238 /// Wrapper to provide functionality to jclass references
239 class JClass : public JavaClass<JClass, JObject, jclass> {
240  public:
241   /// Java type descriptor
242   static constexpr const char* kJavaDescriptor = "Ljava/lang/Class;";
243 
244   /// Get a @local_ref to the super class of this class
245   local_ref<JClass> getSuperclass() const noexcept;
246 
247   /// Register native methods for the class.  Usage looks like this:
248   ///
249   /// classRef->registerNatives({
250   ///     makeNativeMethod("nativeMethodWithAutomaticDescriptor",
251   ///                      methodWithAutomaticDescriptor),
252   ///     makeNativeMethod("nativeMethodWithExplicitDescriptor",
253   ///                      "(Lcom/facebook/example/MyClass;)V",
254   ///                      methodWithExplicitDescriptor),
255   ///     makeCriticalNativeMethod_DO_NOT_USE_OR_YOU_WILL_BE_FIRED("criticalNativeMethodWithAutomaticDescriptor",
256   ///                              criticalNativeMethodWithAutomaticDescriptor),
257   ///     makeCriticalNativeMethod_DO_NOT_USE_OR_YOU_WILL_BE_FIRED("criticalNativeMethodWithExplicitDescriptor",
258   ///                              "(IIF)Z",
259   ///                              criticalNativeMethodWithExplicitDescriptor),
260   ///  });
261   ///
262   /// By default, C++ exceptions raised will be converted to Java exceptions.
263   /// To avoid this and get the "standard" JNI behavior of a crash when a C++
264   /// exception is crashing out of the JNI method, declare the method noexcept.
265   /// This does NOT apply to critical native methods, where exceptions causes
266   /// a crash.
267   void registerNatives(std::initializer_list<JNINativeMethod> methods);
268 
269   /// Check to see if the class is assignable from another class
270   /// @pre cls != nullptr
271   bool isAssignableFrom(alias_ref<JClass> cls) const noexcept;
272 
273   /// Convenience method to lookup the constructor with descriptor as specified
274   /// by the type arguments
275   template <typename F>
276   JConstructor<F> getConstructor() const;
277 
278   /// Convenience method to lookup the constructor with specified descriptor
279   template <typename F>
280   JConstructor<F> getConstructor(const char* descriptor) const;
281 
282   /// Look up the method with given name and descriptor as specified with the
283   /// type arguments
284   template <typename F>
285   JMethod<F> getMethod(const char* name) const;
286 
287   /// Look up the method with given name and descriptor
288   template <typename F>
289   JMethod<F> getMethod(const char* name, const char* descriptor) const;
290 
291   /// Lookup the field with the given name and deduced descriptor
292   template <typename T>
293   JField<PrimitiveOrJniType<T>> getField(const char* name) const;
294 
295   /// Lookup the field with the given name and descriptor
296   template <typename T>
297   JField<PrimitiveOrJniType<T>> getField(
298       const char* name,
299       const char* descriptor) const;
300 
301   /// Lookup the static field with the given name and deduced descriptor
302   template <typename T>
303   JStaticField<PrimitiveOrJniType<T>> getStaticField(const char* name) const;
304 
305   /// Lookup the static field with the given name and descriptor
306   template <typename T>
307   JStaticField<PrimitiveOrJniType<T>> getStaticField(
308       const char* name,
309       const char* descriptor) const;
310 
311   /// Get the primitive value of a static field
312   template <typename T>
313   T getStaticFieldValue(JStaticField<T> field) const noexcept;
314 
315   /// Get and wrap the value of a field in a @ref local_ref
316   template <typename T>
317   local_ref<T*> getStaticFieldValue(JStaticField<T*> field) noexcept;
318 
319   /// Set the value of field. Any Java type is accepted.
320   template <typename T>
321   void setStaticFieldValue(JStaticField<T> field, T value) noexcept;
322   template <
323       typename T,
324       typename = typename std::enable_if<IsPlainJniReference<T>(), T>::type>
325   void setStaticFieldValue(JStaticField<T> field, alias_ref<T> value) noexcept;
326 
327   /// Allocates a new object and invokes the specified constructor
328   template <typename R, typename... Args>
329   local_ref<R> newObject(JConstructor<R(Args...)> constructor, Args... args)
330       const;
331 
332   /// Look up the static method with given name and descriptor as specified with
333   /// the type arguments
334   template <typename F>
335   JStaticMethod<F> getStaticMethod(const char* name) const;
336 
337   /// Look up the static method with given name and descriptor
338   template <typename F>
339   JStaticMethod<F> getStaticMethod(const char* name, const char* descriptor)
340       const;
341 
342   /// Look up the non virtual method with given name and descriptor as specified
343   /// with the type arguments
344   template <typename F>
345   JNonvirtualMethod<F> getNonvirtualMethod(const char* name) const;
346 
347   /// Look up the non virtual method with given name and descriptor
348   template <typename F>
349   JNonvirtualMethod<F> getNonvirtualMethod(
350       const char* name,
351       const char* descriptor) const;
352 
353   /// Get the canonical name of the class
354   local_ref<JString> getCanonicalName();
355 
356  private:
357   jclass self() const noexcept;
358 };
359 
360 // Convenience method to register methods on a class without holding
361 // onto the class object.
362 void registerNatives(
363     const char* name,
364     std::initializer_list<JNINativeMethod> methods);
365 
366 /// Wrapper to provide functionality to jstring references
367 class JString : public JavaClass<JString, JObject, jstring> {
368  public:
369   /// Java type descriptor
370   static constexpr const char* kJavaDescriptor = "Ljava/lang/String;";
371 
372   /// Convenience method to convert a jstring object to a std::string
373   std::string toStdString() const;
374 
375   /// Convenience method to convert a jstring object to a std::u16string
376   std::u16string toU16String() const;
377 };
378 
379 /// Convenience functions to convert a const char*, std::string, or
380 /// std::u16string into a @ref local_ref to a jstring.
381 local_ref<JString> make_jstring(const char* utf8);
382 local_ref<JString> make_jstring(const std::string& utf8);
383 local_ref<JString> make_jstring(const std::u16string& utf16);
384 
385 namespace detail {
386 template <typename Target>
387 class ElementProxy {
388  private:
389   Target* target_;
390   size_t idx_;
391 
392  public:
393   using T = typename Target::javaentry;
394   ElementProxy(Target* target, size_t idx);
395 
396   ElementProxy(const ElementProxy&) noexcept = default;
397 
398   ElementProxy& operator=(const T& o);
399 
400   ElementProxy& operator=(alias_ref<T>& o);
401 
402   ElementProxy& operator=(alias_ref<T>&& o);
403 
404   ElementProxy& operator=(const ElementProxy& o);
405 
406   operator const local_ref<T>() const;
407 
408   operator local_ref<T>();
409 };
410 } // namespace detail
411 
412 namespace detail {
413 class JArray : public JavaClass<JArray, JObject, jarray> {
414  public:
415   // This cannot be used in a scope that derives a descriptor (like in a method
416   // signature). Use a more derived type instead (like JArrayInt or
417   // JArrayClass<T>).
418   static constexpr const char* kJavaDescriptor = nullptr;
419   size_t size() const noexcept;
420 };
421 
422 // This is used so that the JArrayClass<T> javaobject extends jni's
423 // jobjectArray. This class should not be used directly. A general Object[]
424 // should use JArrayClass<jobject>.
425 class JTypeArray : public JavaClass<JTypeArray, JArray, jobjectArray> {
426   // This cannot be used in a scope that derives a descriptor (like in a method
427   // signature).
428   static constexpr const char* kJavaDescriptor = nullptr;
429 };
430 } // namespace detail
431 
432 template <typename T>
433 class JArrayClass : public JavaClass<JArrayClass<T>, detail::JTypeArray> {
434  public:
435   static_assert(
436       IsPlainJniReference<JniType<T>>(),
437       "Element type must be a JNI reference or JavaClass type.");
438   // javaentry is the jni type of an entry in the array (i.e. JObject).
439   using javaentry = T;
440   // javaobject is the jni type of the array.
441   using javaobject =
442       typename JavaClass<JArrayClass<T>, detail::JTypeArray>::javaobject;
443   static constexpr const char* kJavaDescriptor = nullptr;
444   static constexpr auto /* detail::SimpleFixedString<_> */
445   get_instantiated_java_descriptor() {
446     return "[" + jtype_traits<T>::kDescriptor;
447   }
448 
449   static constexpr auto /* detail::SimpleFixedString<_> */
450   get_instantiated_base_name() {
451     return get_instantiated_java_descriptor();
452   }
453 
454   /// Allocate a new array from Java heap, for passing as a JNI parameter or
455   /// return value. NOTE: if using as a return value, you want to call release()
456   /// instead of get() on the smart pointer.
457   static local_ref<javaobject> newArray(size_t count);
458 
459   /// Assign an object to the array.
460   /// Typically you will use the shorthand (*ref)[idx]=value;
461   void setElement(size_t idx, T value);
462 
463   /// Read an object from the array.
464   /// Typically you will use the shorthand
465   ///   T value = (*ref)[idx];
466   /// If you use auto, you'll get an ElementProxy, which may need to be cast.
467   local_ref<T> getElement(size_t idx);
468 
469   /// EXPERIMENTAL SUBSCRIPT SUPPORT
470   /// This implementation of [] returns a proxy object which then has a bunch of
471   /// specializations (adopt_local free function, operator= and casting
472   /// overloads on the ElementProxy) that can make code look like it is dealing
473   /// with a T rather than an obvious proxy. In particular, the proxy in this
474   /// iteration does not read a value and therefore does not create a LocalRef
475   /// until one of these other operators is used. There are certainly holes that
476   /// you may find by using idioms that haven't been tried yet. Consider
477   /// yourself warned. On the other hand, it does make for some idiomatic
478   /// assignment code; see TestBuildStringArray in fbjni_tests for some
479   /// examples.
480   detail::ElementProxy<JArrayClass> operator[](size_t idx);
481 };
482 
483 template <typename T>
484 using jtypeArray = typename JArrayClass<T>::javaobject;
485 
486 template <typename T>
487 local_ref<typename JArrayClass<T>::javaobject> adopt_local_array(
488     jobjectArray ref);
489 
490 template <typename Target>
491 local_ref<typename Target::javaentry> adopt_local(
492     detail::ElementProxy<Target> elementProxy) {
493   return static_cast<local_ref<typename Target::javaentry>>(elementProxy);
494 }
495 
496 template <typename T, typename PinAlloc>
497 class PinnedPrimitiveArray;
498 
499 template <typename T>
500 class PinnedArrayAlloc;
501 template <typename T>
502 class PinnedRegionAlloc;
503 template <typename T>
504 class PinnedCriticalAlloc;
505 
506 /// Wrapper to provide functionality to jarray references.
507 /// This is an empty holder by itself. Construct a PinnedPrimitiveArray to
508 /// actually interact with the elements of the array.
509 template <typename JArrayType>
510 class JPrimitiveArray : public JavaClass<
511                             JPrimitiveArray<JArrayType>,
512                             detail::JArray,
513                             JArrayType> {
514   static_assert(is_jni_primitive_array<JArrayType>(), "");
515 
516  public:
517   static constexpr const char* kJavaDescriptor = nullptr;
518   static constexpr auto /* detail::SimpleFixedString<_> */
519   get_instantiated_java_descriptor() {
520     return jtype_traits<JArrayType>::kDescriptor;
521   }
522   static constexpr auto /* detail::SimpleFixedString<_> */
523   get_instantiated_base_name() {
524     return JPrimitiveArray::get_instantiated_java_descriptor();
525   }
526 
527   using T = typename jtype_traits<JArrayType>::entry_type;
528 
529   static local_ref<JArrayType> newArray(size_t count);
530 
531   void getRegion(jsize start, jsize length, T* buf);
532   std::unique_ptr<T[]> getRegion(jsize start, jsize length);
533   void setRegion(jsize start, jsize length, const T* buf);
534 
535   /// Returns a view of the underlying array. This will either be a "pinned"
536   /// version of the array (in which case changes to one immediately affect the
537   /// other) or a copy of the array (in which cases changes to the view will
538   /// take affect when destroyed or on calls to release()/commit()).
539   PinnedPrimitiveArray<T, PinnedArrayAlloc<T>> pin();
540 
541   /// Returns a view of part of the underlying array. A pinned region is always
542   /// backed by a copy of the region.
543   PinnedPrimitiveArray<T, PinnedRegionAlloc<T>> pinRegion(
544       jsize start,
545       jsize length);
546 
547   /// Returns a view of the underlying array like pin(). However, while the pin
548   /// is held, the code is considered within a "critical region". In a critical
549   /// region, native code must not call JNI functions or make any calls that may
550   /// block on other Java threads. These restrictions make it more likely that
551   /// the view will be "pinned" rather than copied (for example, the VM may
552   /// suspend garbage collection within a critical region).
553   PinnedPrimitiveArray<T, PinnedCriticalAlloc<T>> pinCritical();
554 
555  private:
556   friend class PinnedArrayAlloc<T>;
557   T* getElements(jboolean* isCopy);
558   void releaseElements(T* elements, jint mode);
559 };
560 
561 local_ref<jbooleanArray> make_boolean_array(jsize size);
562 local_ref<jbyteArray> make_byte_array(jsize size);
563 local_ref<jcharArray> make_char_array(jsize size);
564 local_ref<jshortArray> make_short_array(jsize size);
565 local_ref<jintArray> make_int_array(jsize size);
566 local_ref<jlongArray> make_long_array(jsize size);
567 local_ref<jfloatArray> make_float_array(jsize size);
568 local_ref<jdoubleArray> make_double_array(jsize size);
569 
570 using JArrayBoolean = JPrimitiveArray<jbooleanArray>;
571 using JArrayByte = JPrimitiveArray<jbyteArray>;
572 using JArrayChar = JPrimitiveArray<jcharArray>;
573 using JArrayShort = JPrimitiveArray<jshortArray>;
574 using JArrayInt = JPrimitiveArray<jintArray>;
575 using JArrayLong = JPrimitiveArray<jlongArray>;
576 using JArrayFloat = JPrimitiveArray<jfloatArray>;
577 using JArrayDouble = JPrimitiveArray<jdoubleArray>;
578 
579 /// RAII class for pinned primitive arrays
580 /// This currently only supports read/write access to existing java arrays. You
581 /// can't create a primitive array this way yet. This class also pins the entire
582 /// array into memory during the lifetime of the PinnedPrimitiveArray. If you
583 /// need to unpin the array manually, call the release() or abort() functions.
584 /// During a long-running block of code, you should unpin the array as soon as
585 /// you're done with it, to avoid holding up the Java garbage collector.
586 template <typename T, typename PinAlloc>
587 class PinnedPrimitiveArray {
588  public:
589   static_assert(
590       is_jni_primitive<T>::value,
591       "PinnedPrimitiveArray requires primitive jni type.");
592 
593   using ArrayType = typename jtype_traits<T>::array_type;
594 
595   PinnedPrimitiveArray(PinnedPrimitiveArray&&);
596   PinnedPrimitiveArray(const PinnedPrimitiveArray&) = delete;
597   ~PinnedPrimitiveArray() noexcept;
598 
599   PinnedPrimitiveArray& operator=(PinnedPrimitiveArray&&);
600   PinnedPrimitiveArray& operator=(const PinnedPrimitiveArray&) = delete;
601 
602   T* get();
603   void release();
604   /// Unpins the array. If the array is a copy, pending changes are discarded.
605   void abort();
606   /// If the array is a copy, copies pending changes to the underlying java
607   /// array.
608   void commit();
609 
610   bool isCopy() const noexcept;
611 
612   const T& operator[](size_t index) const;
613   T& operator[](size_t index);
614   size_t size() const noexcept;
615 
616  private:
617   alias_ref<ArrayType> array_;
618   size_t start_;
619   T* elements_;
620   jboolean isCopy_;
621   size_t size_;
622 
623   void allocate(alias_ref<ArrayType>, jint start, jint length);
624   void releaseImpl(jint mode);
625   void clear() noexcept;
626 
627   PinnedPrimitiveArray(alias_ref<ArrayType>, jint start, jint length);
628 
629   friend class JPrimitiveArray<typename jtype_traits<T>::array_type>;
630 };
631 
632 struct JStackTraceElement : JavaClass<JStackTraceElement> {
633   static auto constexpr kJavaDescriptor = "Ljava/lang/StackTraceElement;";
634 
635   static local_ref<javaobject> create(
636       const std::string& declaringClass,
637       const std::string& methodName,
638       const std::string& file,
639       int line);
640 
641   std::string getClassName() const;
642   std::string getMethodName() const;
643   std::string getFileName() const;
644   int getLineNumber() const;
645 };
646 
647 /// Wrapper to provide functionality to jthrowable references
648 class JThrowable : public JavaClass<JThrowable, JObject, jthrowable> {
649  public:
650   static constexpr const char* kJavaDescriptor = "Ljava/lang/Throwable;";
651 
652   using JStackTrace = JArrayClass<JStackTraceElement::javaobject>;
653 
654   local_ref<JThrowable> initCause(alias_ref<JThrowable> cause);
655   local_ref<JStackTrace> getStackTrace();
656   local_ref<JString> getMessage();
657   void setStackTrace(alias_ref<JArrayClass<JStackTraceElement::javaobject>>);
658 };
659 
660 #pragma push_macro("PlainJniRefMap")
661 #undef PlainJniRefMap
662 #define PlainJniRefMap(rtype, jtype) \
663   namespace detail {                 \
664   template <>                        \
665   struct RefReprType<jtype> {        \
666     using type = rtype;              \
667   };                                 \
668   }
669 
670 PlainJniRefMap(JArrayBoolean, jbooleanArray) PlainJniRefMap(
671     JArrayByte,
672     jbyteArray) PlainJniRefMap(JArrayChar, jcharArray)
673     PlainJniRefMap(JArrayShort, jshortArray)
674         PlainJniRefMap(JArrayInt, jintArray)
675             PlainJniRefMap(JArrayLong, jlongArray)
676                 PlainJniRefMap(JArrayFloat, jfloatArray)
677                     PlainJniRefMap(JArrayDouble, jdoubleArray)
678                         PlainJniRefMap(JObject, jobject)
679                             PlainJniRefMap(JClass, jclass)
680                                 PlainJniRefMap(JString, jstring)
681                                     PlainJniRefMap(JThrowable, jthrowable)
682 
683 #pragma pop_macro("PlainJniRefMap")
684 
685 } // namespace jni
686 } // namespace facebook
687 
688 #include "CoreClasses-inl.h"
689