text: // Copyright 2004-present Facebook. All Rights Reserved.
  
  #pragma once
  
  #include <cxxreact/NativeModule.h>
  #include <fb/fbjni.h>
  #include <folly/Optional.h>
  
  #include "MethodInvoker.h"
  
  namespace facebook {
  namespace react {
  
  class Instance;
  class MessageQueueThread;
  
  struct JMethodDescriptor : public jni::JavaClass<JMethodDescriptor> {
    static constexpr auto kJavaDescriptor =
      "Lcom/facebook/react/bridge/JavaModuleWrapper$MethodDescriptor;";
  
    jni::local_ref<JReflectMethod::javaobject> getMethod() const;
    std::string getSignature() const;
    std::string getName() const;
    std::string getType() const;
  };
  
  struct JavaModuleWrapper : jni::JavaClass<JavaModuleWrapper> {
    static constexpr auto kJavaDescriptor = "Lcom/facebook/react/bridge/JavaModuleWrapper;";
  
    jni::local_ref<JBaseJavaModule::javaobject> getModule() {
      // This is the call which causes a lazy Java module to actually be
      // created.
      static auto getModule = javaClassStatic()->getMethod<JBaseJavaModule::javaobject()>("getModule");
      return getModule(self());
    }
  
    std::string getName() const {
      static auto getName = javaClassStatic()->getMethod<jstring()>("getName");
      return getName(self())->toStdString();
    }
  
    jni::local_ref<jni::JList<JMethodDescriptor::javaobject>::javaobject> getMethodDescriptors() {
      static auto getMethods = getClass()
        ->getMethod<jni::JList<JMethodDescriptor::javaobject>::javaobject()>("getMethodDescriptors");
      return getMethods(self());
    }
  };
  
  class JavaNativeModule : public NativeModule {
   public:
    JavaNativeModule(
      std::weak_ptr<Instance> instance,
      jni::alias_ref<JavaModuleWrapper::javaobject> wrapper,
      std::shared_ptr<MessageQueueThread> messageQueueThread)
    : instance_(std::move(instance))
    , wrapper_(make_global(wrapper))
    , messageQueueThread_(std::move(messageQueueThread)) {}
  
    std::string getName() override;
    folly::dynamic getConstants() override;
    std::vector<MethodDescriptor> getMethods() override;
    void invoke(unsigned int reactMethodId, folly::dynamic&& params) override;
    MethodCallResult callSerializableNativeHook(unsigned int reactMethodId, folly::dynamic&& params) override;
  
   private:
    std::weak_ptr<Instance> instance_;
    jni::global_ref<JavaModuleWrapper::javaobject> wrapper_;
    std::shared_ptr<MessageQueueThread> messageQueueThread_;
    std::vector<folly::Optional<MethodInvoker>> syncMethods_;
  };
  
  // Experimental new implementation that uses direct method invocation
  class NewJavaNativeModule : public NativeModule {
   public:
    NewJavaNativeModule(
      std::weak_ptr<Instance> instance,
      jni::alias_ref<JavaModuleWrapper::javaobject> wrapper,
      std::shared_ptr<MessageQueueThread> messageQueueThread);
  
    std::string getName() override;
    std::vector<MethodDescriptor> getMethods() override;
    folly::dynamic getConstants() override;
    void invoke(unsigned int reactMethodId, folly::dynamic&& params) override;
    MethodCallResult callSerializableNativeHook(unsigned int reactMethodId, folly::dynamic&& params) override;
  
   private:
    std::weak_ptr<Instance> instance_;
    jni::global_ref<JavaModuleWrapper::javaobject> wrapper_;
    jni::global_ref<JBaseJavaModule::javaobject> module_;
    std::shared_ptr<MessageQueueThread> messageQueueThread_;
    std::vector<MethodInvoker> methods_;
    std::vector<MethodDescriptor> methodDescriptors_;
  
    MethodCallResult invokeInner(unsigned int reactMethodId, folly::dynamic&& params);
  };
  
  }}
  