#pragma once #include #include #include namespace jni { template < class TheTag > class Class; template < class TheTag, class > class Field; template < class TheTag, class > class Method; class ObjectBase { protected: jobject* ptr = nullptr; explicit ObjectBase(std::nullptr_t = nullptr) {} explicit ObjectBase(jobject* p) : ptr(p) {} ~ObjectBase() = default; void reset(jobject* p) { ptr = p; } public: explicit operator bool() const { return ptr; } friend bool operator==(const ObjectBase& a, const ObjectBase& b) { return a.ptr == b.ptr; } friend bool operator!=(const ObjectBase& a, const ObjectBase& b) { return !( a == b ); } template < class OtherTag > bool IsInstanceOf(JNIEnv& env, const Class& clazz) const { return jni::IsInstanceOf(env, ptr, *clazz); } }; template < class TheTag = ObjectTag > class Object : public TagTraits::SuperType { public: using TagType = TheTag; using SuperType = typename TagTraits::SuperType; using UntaggedType = typename TagTraits::UntaggedType; explicit Object(UntaggedType* p) : SuperType(p) {} protected: explicit Object(std::nullptr_t = nullptr) {} Object(const Object&) = delete; Object& operator=(const Object&) = delete; public: UntaggedType* get() const { return reinterpret_cast(this->ptr); } UntaggedType& operator*() const { return *get(); } template < class T > auto Get(JNIEnv& env, const Field& field) const -> std::enable_if_t< IsPrimitive::value, T > { return GetField(env, get(), field); } template < class T > auto Get(JNIEnv& env, const Field& field) const -> std::enable_if_t< !IsPrimitive::value, Local > { return Local(env, reinterpret_cast(GetField(env, get(), field))); } template < class T > auto Set(JNIEnv& env, const Field& field, T value) const -> std::enable_if_t< IsPrimitive::value > { SetField(env, get(), field, value); } template < class Expected, class Actual > auto Set(JNIEnv& env, const Field& field, const Actual& value) const -> std::enable_if_t< !IsPrimitive::value && std::is_convertible::value > { SetField(env, get(), field, value.get()); } template < class R, class... ExpectedArgs, class... ActualArgs > auto Call(JNIEnv& env, const Method& method, const ActualArgs&... args) const -> std::enable_if_t< IsPrimitive::value && Conjunction...>::value, R > { return CallMethod(env, get(), method, Untag(args)...); } template < class R, class... ExpectedArgs, class... ActualArgs > auto Call(JNIEnv& env, const Method& method, const ActualArgs&... args) const -> std::enable_if_t< !IsPrimitive::value && !std::is_void::value && Conjunction...>::value, Local > { return Local(env, reinterpret_cast(CallMethod(env, get(), method, Untag(args)...))); } template < class... ExpectedArgs, class... ActualArgs > auto Call(JNIEnv& env, const Method& method, const ActualArgs&... args) const -> std::enable_if_t< Conjunction...>::value > { CallMethod(env, get(), method, Untag(args)...); } template < class R, class... ExpectedArgs, class... ActualArgs > auto CallNonvirtual(JNIEnv& env, const Class& clazz, const Method& method, const ActualArgs&... args) const -> std::enable_if_t< IsPrimitive::value && Conjunction...>::value, R > { return CallNonvirtualMethod(env, get(), clazz, method, Untag(args)...); } template < class R, class... ExpectedArgs, class... ActualArgs > auto CallNonvirtual(JNIEnv& env, const Class& clazz, const Method& method, const ActualArgs&... args) const -> std::enable_if_t< !IsPrimitive::value && !std::is_void::value && Conjunction...>::value, Local > { return Local(env, reinterpret_cast(CallNonvirtualMethod(env, get(), clazz, method, Untag(args)...))); } template < class... ExpectedArgs, class... ActualArgs > auto CallNonvirtual(JNIEnv& env, const Class& clazz, const Method& method, const ActualArgs&... args) const -> std::enable_if_t< Conjunction...>::value > { CallNonvirtualMethod(env, get(), clazz, method, Untag(args)...); } }; template < class OutTagType, class T > Local> Cast(JNIEnv& env, const Class& clazz, const T& object) { if (!object.IsInstanceOf(env, clazz)) { ThrowNew(env, FindClass(env, "java/lang/ClassCastException")); } return Local>(env, reinterpret_cast::UntaggedType*>(NewLocal(env, object).release())); } }