Skip to content

ArrayTypeMismatchException when serializing nested Dictionary on Android device (after HybridCLR hot update) #621

@LiuZhanMingFpy

Description

@LiuZhanMingFpy

JEngine Version

1.1.5

Unity Version

2022.3.62f2

Target Platform

Android

Bug Description

Nino serialization throws System.ArrayTypeMismatchException when serializing a class containing
nested Dictionary<int, CustomClass> structures.

 **Important**: This bug **only reproduces on Android real device**, NOT in Unity Editor or other
 platforms.

 The issue occurs under these conditions:
 1. Running on **Android real device** (not Editor)
 2. After entering **hot update scene** via HybridCLR
 3. Nino generators have been properly initialized:
    - `HotUpdate.Code.NinoGen.Serializer.Init()`
    - `HotUpdate.Code.NinoGen.Deserializer.Init()`
    - `HotUpdate.Code.NinoGen.NinoBuiltInTypesRegistration.Init()`
 4. Then dynamically create GameObject and add the component with nested Dictionary serialization

 Data structure:
 - Class `Root` has `Dictionary<int, Level1>`
 - Class `Level1` has `Dictionary<int, Level2>`
 - All classes are marked with `[NinoType]`

Steps to Reproduce

  1. Build and deploy to Android real device
    2. Launch app and complete hot update process
    3. Enter hot update scene
    4. In EntryPoint method, initialize Nino:
    HotUpdate.Code.NinoGen.Serializer.Init();
    HotUpdate.Code.NinoGen.Deserializer.Init();
    HotUpdate.Code.NinoGen.NinoBuiltInTypesRegistration.Init();
  2. Dynamically create test component:
    var a = new GameObject();
    a.AddComponent();

Expected Behavior

Serialization and deserialization should work correctly for nested Dictionary<int, CustomClass>structures, just like single-level dictionaries.

Error Logs

[NinoRepro] Exception: System.ArrayTypeMismatchException
     Attempted to access an element as a type incompatible with the array.
       at Nino.Core.CachedSerializer`1[T].SerializePolymorphic (T val, Nino.Core.Writer& writer) [0x00000] in
      <00000000000000000000000000000000>:0
       at Nino.Core.CachedSerializer`1[T].Serialize (T val, Nino.Core.Writer& writer) [0x00000] in
     <00000000000000000000000000000000>:0
       at Nino.Core.NinoSerializer.Serialize[T] (T value, Nino.Core.Writer& writer) [0x00000] in
     <00000000000000000000000000000000>:0
       at Nino.Core.NinoSerializer.Serialize[T] (T value) [0x00000] in <00000000000000000000000000000000>:0

Additional Context

 using System;
     using System.Collections.Generic;
     using Nino.Core;
     using UnityEngine;

     public class NinoNestedDictionaryRepro : MonoBehaviour
     {
         [NinoType]
         public class Root
         {
             public Dictionary<int, Level1> RegionStates = new();
             public float SavedRemainingTime;
             public int CurrentWorldMapId;
         }

         [NinoType]
         public class Level1
         {
             public int RegionId;
             public Dictionary<int, Level2> ResourceStates = new();
         }

         [NinoType]
         public class Level2
         {
             public int ResourceId;
             public int RemainingCount;
             public int MaxCount;
         }

         private void Start()
         {
             try
             {
                 var src = CreateSample();
                 byte[] bytes = NinoSerializer.Serialize(src);  // ❌ Exception here
                 Debug.Log($"[NinoRepro] Serialize OK, bytes={bytes.Length}");

                 var dst = NinoDeserializer.Deserialize<Root>(bytes);
                 Debug.Log($"[NinoRepro] Deserialize OK, regions={dst.RegionStates.Count}");
             }
             catch (Exception ex)
             {
                 Debug.LogError($"[NinoRepro] Exception:
     {ex.GetType().FullName}\n{ex.Message}\n{ex.StackTrace}");
             }
         }

         private static Root CreateSample()
         {
             var root = new Root
             {
                 SavedRemainingTime = 12.34f,
                 CurrentWorldMapId = 7
             };

             var region = new Level1 { RegionId = 1001 };
             region.ResourceStates[2002] = new Level2
             {
                 ResourceId = 2002,
                 RemainingCount = 3,
                 MaxCount = 10
             };

             root.RegionStates[region.RegionId] = region;
             return root;
         }
     }

Checklist

  • I have searched existing issues to ensure this bug hasn't been reported before
  • I have tested with the latest version of JEngine

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions