nitro icon indicating copy to clipboard operation
nitro copied to clipboard

`Record<string, number>` generates wrong code on Kotlin

Open OrfeasZ opened this issue 1 month ago • 2 comments

What's happening?

Using a typescript type with a nested record type results in C++ compiler errors in nitrogen-generated code, due to lack of JSI-type wrapping.

Reproduceable Code

interface DataPoint {
  point: Record<string, number>;
  tooltipText?: string;
}

Relevant log output

.../fbjni-0.7.0/prefab/modules/fbjni/include/fbjni/detail/References.h:190:25: error: implicit instantiation of undefined template 'facebook::jni::detail::RefReprType<double>'

Device

Android

Nitro Modules Version

0.31.7

Nitrogen Version

0.31.7

Can you reproduce this issue in the Nitro Example app here?

I didn't try (⚠️ your issue might get ignored & closed if you don't try this)

Additional information

OrfeasZ avatar Nov 24 '25 20:11 OrfeasZ

The TS code above generates the following C++ code:

    DataPoint toCpp() const {
      static const auto clazz = javaClassStatic();
      static const auto fieldPoint = clazz->getField<jni::JMap<jni::JString, double>>("point");
      jni::local_ref<jni::JMap<jni::JString, double>> point = this->getFieldValue(fieldPoint);
      static const auto fieldTooltipText = clazz->getField<jni::JString>("tooltipText");
      jni::local_ref<jni::JString> tooltipText = this->getFieldValue(fieldTooltipText);
      return DataPoint(
        [&]() {
          std::unordered_map<std::string, double> __map;
          __map.reserve(point->size());
          for (const auto& __entry : *point) {
            __map.emplace(__entry.first->toStdString(), __entry.second);
          }
          return __map;
        }(),
        tooltipText != nullptr ? std::make_optional(tooltipText->toStdString()) : std::nullopt
      );
    }

Notice that the point map is declared as jni::JMap<jni::JString, double> instead of jni::JMap<jni::JString, jsi::JDouble>. This in turn results in the compiler error above when trying to iterate over it.

Patching the file manually to use jsi::JDouble (as below), resolves the issue:

diff --git a/snip/nitrogen/generated/android/c++/JDataPoint.hpp b/snip/nitrogen/generated/android/c++/JDataPoint.hpp
index 7e561156..756a82b9 100644
--- a/snip/nitrogen/generated/android/c++/JDataPoint.hpp
+++ b/snip/nitrogen/generated/android/c++/JDataPoint.hpp
@@ -33,8 +33,8 @@ namespace margelo::nitro::mymodule {
     [[nodiscard]]
     DataPoint toCpp() const {
       static const auto clazz = javaClassStatic();
-      static const auto fieldPoint = clazz->getField<jni::JMap<jni::JString, double>>("point");
-      jni::local_ref<jni::JMap<jni::JString, double>> point = this->getFieldValue(fieldPoint);
+      static const auto fieldPoint = clazz->getField<jni::JMap<jni::JString, jni::JDouble>>("point");
+      jni::local_ref<jni::JMap<jni::JString, jni::JDouble>> point = this->getFieldValue(fieldPoint);
       static const auto fieldTooltipText = clazz->getField<jni::JString>("tooltipText");
       jni::local_ref<jni::JString> tooltipText = this->getFieldValue(fieldTooltipText);
       return DataPoint(
@@ -42,7 +42,7 @@ namespace margelo::nitro::mymodule {
           std::unordered_map<std::string, double> __map;
           __map.reserve(point->size());
           for (const auto& __entry : *point) {
-            __map.emplace(__entry.first->toStdString(), __entry.second);
+            __map.emplace(__entry.first->toStdString(), __entry.second->doubleValue());
           }
           return __map;
         }(),
@@ -56,15 +56,15 @@ namespace margelo::nitro::mymodule {
      */
     [[maybe_unused]]
     static jni::local_ref<JDataPoint::javaobject> fromCpp(const DataPoint& value) {
-      using JSignature = JDataPoint(jni::alias_ref<jni::JMap<jni::JString, double>>, jni::alias_ref<jni::JString>);
+      using JSignature = JDataPoint(jni::alias_ref<jni::JMap<jni::JString, jni::JDouble>>, jni::alias_ref<jni::JString>);
       static const auto clazz = javaClassStatic();
       static const auto create = clazz->getStaticMethod<JSignature>("fromCpp");
       return create(
         clazz,
-        [&]() -> jni::local_ref<jni::JMap<jni::JString, double>> {
-          auto __map = jni::JHashMap<jni::JString, double>::create(value.point.size());
+        [&]() -> jni::local_ref<jni::JMap<jni::JString, jni::JDouble>> {
+          auto __map = jni::JHashMap<jni::JString, jni::JDouble>::create(value.point.size());
           for (const auto& __entry : value.point) {
-            __map->put(jni::make_jstring(__entry.first), __entry.second);
+            __map->put(jni::make_jstring(__entry.first), jni::JDouble::valueOf(__entry.second));
           }
           return __map;
         }(),

OrfeasZ avatar Nov 24 '25 20:11 OrfeasZ

fixed in https://github.com/mrousavy/nitro/pull/1061

mrousavy avatar Nov 24 '25 20:11 mrousavy