diff --git a/packages/nitrogen/src/syntax/kotlin/KotlinHybridObjectRegistration.ts b/packages/nitrogen/src/syntax/kotlin/KotlinHybridObjectRegistration.ts index 904ed6fd..8c664ecd 100644 --- a/packages/nitrogen/src/syntax/kotlin/KotlinHybridObjectRegistration.ts +++ b/packages/nitrogen/src/syntax/kotlin/KotlinHybridObjectRegistration.ts @@ -24,10 +24,6 @@ export function createJNIHybridObjectRegistration({ }: Props): JNIHybridObjectRegistration { const { JHybridTSpec } = getHybridObjectName(hybridObjectName) const jniNamespace = NitroConfig.getAndroidPackage('c++/jni', jniClassName) - const javaNamespace = NitroConfig.getAndroidPackage( - 'java/kotlin', - jniClassName - ) return { requiredImports: [ @@ -37,42 +33,18 @@ export function createJNIHybridObjectRegistration({ language: 'c++', space: 'system', }, + { + name: 'NitroModules/DefaultConstructableObject.hpp', + language: 'c++', + space: 'system', + }, ], cppCode: ` HybridObjectRegistry::registerHybridObjectConstructor( "${hybridObjectName}", []() -> std::shared_ptr { - static jni::alias_ref javaClass; - static jni::JConstructor<${JHybridTSpec}::javaobject()> defaultConstructor; - static bool isInitialized = false; - try { - if (!isInitialized) { - javaClass = jni::findClassStatic("${jniNamespace}"); - defaultConstructor = javaClass->getConstructor<${JHybridTSpec}::javaobject()>(); - isInitialized = true; - } - } catch (const jni::JniException& exc) { - std::string message = exc.what(); - if (message.find("ClassNotFoundException")) { - throw std::runtime_error("Couldn't find class \`${javaNamespace}\`!\\n" - "- Make sure the class exists in the specified namespace.\\n" - "- Make sure the class is not stripped. If you are using ProGuard, add \`@Keep\` and \`@DoNotStrip\` annotations to ${jniClassName}."); - } else if (message.find("NoSuchMethodError")) { - throw std::runtime_error("Couldn't find ${jniClassName}'s default constructor!\\n" - "- If you want to autolink ${jniClassName}, add a default constructor that takes zero arguments.\\n" - "- If you need arguments to create instances of ${jniClassName}, create a separate HybridObject that acts as a factory for this HybridObject to create instances of it with parameters.\\n" - "- If you already have a default constructor, make sure it is not being stripped. If you are using ProGuard, add \`@Keep\` and \`@DoNotStrip\` annotations to the default constructor."); - } else { - throw; - } - } - - auto instance = javaClass->newObject(defaultConstructor); -#ifdef NITRO_DEBUG - if (instance == nullptr) [[unlikely]] { - throw std::runtime_error("Failed to create an instance of \\"${JHybridTSpec}\\" - the constructor returned null!"); - } -#endif + static DefaultConstructableObject<${JHybridTSpec}::javaobject> object("${jniNamespace}"); + auto instance = object.create(); auto globalRef = jni::make_global(instance); return JNISharedPtr::make_shared_from_jni<${JHybridTSpec}>(globalRef); } diff --git a/packages/react-native-nitro-image/nitrogen/generated/android/NitroImageOnLoad.cpp b/packages/react-native-nitro-image/nitrogen/generated/android/NitroImageOnLoad.cpp index 5801561b..e9406c02 100644 --- a/packages/react-native-nitro-image/nitrogen/generated/android/NitroImageOnLoad.cpp +++ b/packages/react-native-nitro-image/nitrogen/generated/android/NitroImageOnLoad.cpp @@ -21,6 +21,7 @@ #include "JHybridBaseSpec.hpp" #include "JHybridChildSpec.hpp" #include +#include #include "HybridTestObjectCpp.hpp" namespace margelo::nitro::image { @@ -49,37 +50,8 @@ int initialize(JavaVM* vm) { HybridObjectRegistry::registerHybridObjectConstructor( "ImageFactory", []() -> std::shared_ptr { - static jni::alias_ref javaClass; - static jni::JConstructor defaultConstructor; - static bool isInitialized = false; - try { - if (!isInitialized) { - javaClass = jni::findClassStatic("com/margelo/nitro/image/ImageFactory"); - defaultConstructor = javaClass->getConstructor(); - isInitialized = true; - } - } catch (const jni::JniException& exc) { - std::string message = exc.what(); - if (message.find("ClassNotFoundException")) { - throw std::runtime_error("Couldn't find class `com.margelo.nitro.image.ImageFactory`!\n" - "- Make sure the class exists in the specified namespace.\n" - "- Make sure the class is not stripped. If you are using ProGuard, add `@Keep` and `@DoNotStrip` annotations to ImageFactory."); - } else if (message.find("NoSuchMethodError")) { - throw std::runtime_error("Couldn't find ImageFactory's default constructor!\n" - "- If you want to autolink ImageFactory, add a default constructor that takes zero arguments.\n" - "- If you need arguments to create instances of ImageFactory, create a separate HybridObject that acts as a factory for this HybridObject to create instances of it with parameters.\n" - "- If you already have a default constructor, make sure it is not being stripped. If you are using ProGuard, add `@Keep` and `@DoNotStrip` annotations to the default constructor."); - } else { - throw; - } - } - - auto instance = javaClass->newObject(defaultConstructor); - #ifdef NITRO_DEBUG - if (instance == nullptr) [[unlikely]] { - throw std::runtime_error("Failed to create an instance of \"JHybridImageFactorySpec\" - the constructor returned null!"); - } - #endif + static DefaultConstructableObject object("com/margelo/nitro/image/ImageFactory"); + auto instance = object.create(); auto globalRef = jni::make_global(instance); return JNISharedPtr::make_shared_from_jni(globalRef); } @@ -96,37 +68,8 @@ int initialize(JavaVM* vm) { HybridObjectRegistry::registerHybridObjectConstructor( "TestObjectSwiftKotlin", []() -> std::shared_ptr { - static jni::alias_ref javaClass; - static jni::JConstructor defaultConstructor; - static bool isInitialized = false; - try { - if (!isInitialized) { - javaClass = jni::findClassStatic("com/margelo/nitro/image/HybridTestObjectKotlin"); - defaultConstructor = javaClass->getConstructor(); - isInitialized = true; - } - } catch (const jni::JniException& exc) { - std::string message = exc.what(); - if (message.find("ClassNotFoundException")) { - throw std::runtime_error("Couldn't find class `com.margelo.nitro.image.HybridTestObjectKotlin`!\n" - "- Make sure the class exists in the specified namespace.\n" - "- Make sure the class is not stripped. If you are using ProGuard, add `@Keep` and `@DoNotStrip` annotations to HybridTestObjectKotlin."); - } else if (message.find("NoSuchMethodError")) { - throw std::runtime_error("Couldn't find HybridTestObjectKotlin's default constructor!\n" - "- If you want to autolink HybridTestObjectKotlin, add a default constructor that takes zero arguments.\n" - "- If you need arguments to create instances of HybridTestObjectKotlin, create a separate HybridObject that acts as a factory for this HybridObject to create instances of it with parameters.\n" - "- If you already have a default constructor, make sure it is not being stripped. If you are using ProGuard, add `@Keep` and `@DoNotStrip` annotations to the default constructor."); - } else { - throw; - } - } - - auto instance = javaClass->newObject(defaultConstructor); - #ifdef NITRO_DEBUG - if (instance == nullptr) [[unlikely]] { - throw std::runtime_error("Failed to create an instance of \"JHybridTestObjectSwiftKotlinSpec\" - the constructor returned null!"); - } - #endif + static DefaultConstructableObject object("com/margelo/nitro/image/HybridTestObjectKotlin"); + auto instance = object.create(); auto globalRef = jni::make_global(instance); return JNISharedPtr::make_shared_from_jni(globalRef); } @@ -134,37 +77,8 @@ int initialize(JavaVM* vm) { HybridObjectRegistry::registerHybridObjectConstructor( "Base", []() -> std::shared_ptr { - static jni::alias_ref javaClass; - static jni::JConstructor defaultConstructor; - static bool isInitialized = false; - try { - if (!isInitialized) { - javaClass = jni::findClassStatic("com/margelo/nitro/image/HybridBase"); - defaultConstructor = javaClass->getConstructor(); - isInitialized = true; - } - } catch (const jni::JniException& exc) { - std::string message = exc.what(); - if (message.find("ClassNotFoundException")) { - throw std::runtime_error("Couldn't find class `com.margelo.nitro.image.HybridBase`!\n" - "- Make sure the class exists in the specified namespace.\n" - "- Make sure the class is not stripped. If you are using ProGuard, add `@Keep` and `@DoNotStrip` annotations to HybridBase."); - } else if (message.find("NoSuchMethodError")) { - throw std::runtime_error("Couldn't find HybridBase's default constructor!\n" - "- If you want to autolink HybridBase, add a default constructor that takes zero arguments.\n" - "- If you need arguments to create instances of HybridBase, create a separate HybridObject that acts as a factory for this HybridObject to create instances of it with parameters.\n" - "- If you already have a default constructor, make sure it is not being stripped. If you are using ProGuard, add `@Keep` and `@DoNotStrip` annotations to the default constructor."); - } else { - throw; - } - } - - auto instance = javaClass->newObject(defaultConstructor); - #ifdef NITRO_DEBUG - if (instance == nullptr) [[unlikely]] { - throw std::runtime_error("Failed to create an instance of \"JHybridBaseSpec\" - the constructor returned null!"); - } - #endif + static DefaultConstructableObject object("com/margelo/nitro/image/HybridBase"); + auto instance = object.create(); auto globalRef = jni::make_global(instance); return JNISharedPtr::make_shared_from_jni(globalRef); } @@ -172,37 +86,8 @@ int initialize(JavaVM* vm) { HybridObjectRegistry::registerHybridObjectConstructor( "Child", []() -> std::shared_ptr { - static jni::alias_ref javaClass; - static jni::JConstructor defaultConstructor; - static bool isInitialized = false; - try { - if (!isInitialized) { - javaClass = jni::findClassStatic("com/margelo/nitro/image/HybridChild"); - defaultConstructor = javaClass->getConstructor(); - isInitialized = true; - } - } catch (const jni::JniException& exc) { - std::string message = exc.what(); - if (message.find("ClassNotFoundException")) { - throw std::runtime_error("Couldn't find class `com.margelo.nitro.image.HybridChild`!\n" - "- Make sure the class exists in the specified namespace.\n" - "- Make sure the class is not stripped. If you are using ProGuard, add `@Keep` and `@DoNotStrip` annotations to HybridChild."); - } else if (message.find("NoSuchMethodError")) { - throw std::runtime_error("Couldn't find HybridChild's default constructor!\n" - "- If you want to autolink HybridChild, add a default constructor that takes zero arguments.\n" - "- If you need arguments to create instances of HybridChild, create a separate HybridObject that acts as a factory for this HybridObject to create instances of it with parameters.\n" - "- If you already have a default constructor, make sure it is not being stripped. If you are using ProGuard, add `@Keep` and `@DoNotStrip` annotations to the default constructor."); - } else { - throw; - } - } - - auto instance = javaClass->newObject(defaultConstructor); - #ifdef NITRO_DEBUG - if (instance == nullptr) [[unlikely]] { - throw std::runtime_error("Failed to create an instance of \"JHybridChildSpec\" - the constructor returned null!"); - } - #endif + static DefaultConstructableObject object("com/margelo/nitro/image/HybridChild"); + auto instance = object.create(); auto globalRef = jni::make_global(instance); return JNISharedPtr::make_shared_from_jni(globalRef); } diff --git a/packages/react-native-nitro-modules/android/src/main/cpp/registry/DefaultConstructableObject.hpp b/packages/react-native-nitro-modules/android/src/main/cpp/registry/DefaultConstructableObject.hpp new file mode 100644 index 00000000..959bd814 --- /dev/null +++ b/packages/react-native-nitro-modules/android/src/main/cpp/registry/DefaultConstructableObject.hpp @@ -0,0 +1,79 @@ +// +// DefaultConstructableObject.hpp +// react-native-nitro +// +// Created by Marc Rousavy on 11.11.24. +// + +#pragma once + +#include "NitroDefines.hpp" +#include + +namespace margelo::nitro { + +using namespace facebook; + +template +class DefaultConstructableObject { +public: + explicit DefaultConstructableObject(const char* javaClassDescriptor) { + try { + // Find JNI class and default constructor + _javaClass = jni::findClassStatic(javaClassDescriptor); + _defaultConstructor = _javaClass->getConstructor(); + } catch (const jni::JniException& exc) { + std::string message = exc.what(); + std::string descriptor = javaClassDescriptor; + std::string className = findClassName(descriptor); + if (message.find("ClassNotFoundException")) { + // Java class cannot be found + throw std::runtime_error( + "Couldn't find class `" + descriptor + + "`!\n" + "- Make sure the class exists in the specified namespace.\n" + "- Make sure the class is not stripped. If you are using ProGuard, add `@Keep` and `@DoNotStrip` annotations to `" + + className + "`."); + } else if (message.find("NoSuchMethodError")) { + // Default Constructor cannot be found + throw std::runtime_error( + "Couldn't find " + className + + "'s default constructor!\n" + "- If you want to autolink " + + className + + ", add a default constructor that takes zero arguments.\n" + "- If you need arguments to create instances of " + + className + + ", create a separate HybridObject that acts as a factory for this HybridObject to create instances of it with parameters.\n" + "- If you already have a default constructor, make sure it is not being stripped. If you are using ProGuard, add `@Keep` and " + "`@DoNotStrip` annotations to the default constructor."); + } else { + throw; + } + } + } + +public: + jni::local_ref create() const { + // Calls the class's default constructor + auto instance = _javaClass->newObject(_defaultConstructor); +#ifdef NITRO_DEBUG + if (instance == nullptr) [[unlikely]] { + throw std::runtime_error("Failed to create an instance of \"JHybridTestObjectSwiftKotlinSpec\" - the constructor returned null!"); + } +#endif + return instance; + } + +private: + static std::string findClassName(const std::string& jniDescriptor) { + size_t lastSlash = jniDescriptor.rfind('/'); + return jniDescriptor.substr(lastSlash + 1); + } + +private: + jni::alias_ref _javaClass; + jni::JConstructor _defaultConstructor; +}; + +} // namespace margelo::nitro