This is an automated email from the ASF dual-hosted git repository.

chaokunyang pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/fory.git


The following commit(s) were added to refs/heads/main by this push:
     new 55879b788 feat(dart): align dart xlang serialization (#3322)
55879b788 is described below

commit 55879b788a22a7e1e565592f3106eaab8c22e1fe
Author: Shawn Yang <[email protected]>
AuthorDate: Wed Feb 11 10:20:07 2026 +0800

    feat(dart): align dart xlang serialization (#3322)
    
    ## Why?
    
    Dart xlang serialization was stale and inconsistent with
    `docs/specification/xlang_serialization_spec.md`, which caused
    cross-language incompatibilities with Java xlang tests.
    
    ## What does this PR do?
    
    - Adds a Dart xlang test harness in Java: `DartXlangTest`.
    - Adds Dart cross-language test entrypoint:
    `dart/packages/fory-test/test/cross_lang_test/xlang_test_main.dart`.
    - Aligns Dart xlang read/write behavior with Java/spec for core paths:
      - collection/list/set element header flags and read/write paths,
      - map chunk header + key/value chunk read/write paths,
    - non-ref typed read/write without per-element ref headers when
    required.
    - Fixes Dart xlang type resolution and compatibility details used by
    tests:
      - set serializer assignment in type-wrap resolution,
      - struct hash signedness consistency,
      - default ref-tracking behavior alignment for xlang compatibility.
    - Adds Dart xlang CI job in `.github/workflows/ci.yml`.
    - Fixes existing Dart CI codegen step to be non-interactive with:
      - `dart run build_runner build --delete-conflicting-outputs`.
    
    Validation performed:
    - `ENABLE_FORY_DEBUG_OUTPUT=1 FORY_DART_JAVA_CI=1 mvn -T16
    --no-transfer-progress -pl fory-core -am test
    -Dtest=org.apache.fory.xlang.DartXlangTest
    -Dsurefire.failIfNoSpecifiedTests=false`
    - Dart CI pipeline checks (`dart pub get`, `dart run build_runner build
    --delete-conflicting-outputs`, `dart test`, `dart analyze`)
    
    ## Related issues
    
    N/A
    
    ## Does this PR introduce any user-facing change?
    
    Dart cross-language serialization behavior is now aligned with xlang
    spec/Java behavior.
    
    - [ ] Does this PR introduce any public API change?
    - [ ] Does this PR introduce any binary protocol compatibility change?
    
    ## Benchmark
    
    N/A
---
 .github/workflows/ci.yml                           |  41 +-
 .../test/cross_lang_test/xlang_test_main.dart      | 871 +++++++++++++++++++++
 dart/packages/fory/lib/src/base_fory.dart          |  10 +-
 dart/packages/fory/lib/src/config/fory_config.dart |  20 +-
 .../fory/lib/src/deserialize_coordinator.dart      |  36 +-
 .../lib/src/exception/registration_exception.dart  |  44 +-
 dart/packages/fory/lib/src/fory_context.dart       |  73 +-
 dart/packages/fory/lib/src/fory_impl.dart          |  27 +-
 .../fory/lib/src/manager/fory_config_manager.dart  |   4 +-
 .../lib/src/resolver/impl/xtype_resolver_impl.dart | 617 ++++++++++++++-
 .../lib/src/resolver/struct_hash_resolver.dart     | 132 ++--
 .../fory/lib/src/resolver/xtype_resolver.dart      |  11 +-
 .../fory/lib/src/serialize_coordinator.dart        |  54 +-
 .../fory/lib/src/serializer/class_serializer.dart  |  96 ++-
 .../serializer/collection/iterable_serializer.dart | 198 ++++-
 .../collection/list/list_serializer.dart           |  81 +-
 .../serializer/collection/map/map_serializer.dart  | 465 ++++++++---
 .../serializer/collection/set/set_serializer.dart  |  79 +-
 .../java/org/apache/fory/xlang/DartXlangTest.java  | 294 +++++++
 19 files changed, 2748 insertions(+), 405 deletions(-)

diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index d6e4962be..d4ddfe533 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -679,6 +679,45 @@ jobs:
       - name: Run Go IDL Tests
         run: ./integration_tests/idl_tests/run_go_tests.sh
 
+  dart_xlang:
+    name: Dart Xlang Test
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v5
+      - name: Set up JDK 21
+        uses: actions/setup-java@v4
+        with:
+          java-version: 21
+          distribution: "temurin"
+      - name: Cache Maven local repository
+        uses: actions/cache@v4
+        with:
+          path: ~/.m2/repository
+          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
+          restore-keys: |
+            ${{ runner.os }}-maven-
+      - name: Install Dart SDK
+        run: |
+          DART_VERSION=3.6.1
+          wget -q 
https://storage.googleapis.com/dart-archive/channels/stable/release/${DART_VERSION}/sdk/dartsdk-linux-x64-release.zip
+          unzip -q dartsdk-linux-x64-release.zip
+          echo "$PWD/dart-sdk/bin" >> $GITHUB_PATH
+      - name: Display Dart version
+        run: dart --version
+      - name: Get Dart dependencies
+        run: |
+          cd dart
+          dart pub get
+      - name: Run Dart Xlang Test
+        env:
+          FORY_DART_JAVA_CI: "1"
+          ENABLE_FORY_DEBUG_OUTPUT: "1"
+        run: |
+          cd java
+          mvn -T16 --no-transfer-progress clean install -DskipTests
+          cd fory-core
+          mvn -T16 --no-transfer-progress test 
-Dtest=org.apache.fory.xlang.DartXlangTest
+
   dart:
     name: Dart CI
     runs-on: ubuntu-latest
@@ -701,7 +740,7 @@ jobs:
       - name: Generate code
         run: |
           cd dart/packages/fory-test
-          dart run build_runner build
+          dart run build_runner build --delete-conflicting-outputs
       - name: Run tests
         run: |
           cd dart/packages/fory-test
diff --git a/dart/packages/fory-test/test/cross_lang_test/xlang_test_main.dart 
b/dart/packages/fory-test/test/cross_lang_test/xlang_test_main.dart
new file mode 100644
index 000000000..a655a519a
--- /dev/null
+++ b/dart/packages/fory-test/test/cross_lang_test/xlang_test_main.dart
@@ -0,0 +1,871 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import 'dart:io';
+import 'dart:typed_data';
+import 'package:fory/fory.dart';
+
+String _getDataFile() {
+  final String? dataFile = Platform.environment['DATA_FILE'];
+  if (dataFile == null || dataFile.isEmpty) {
+    throw StateError('DATA_FILE environment variable not set');
+  }
+  return dataFile;
+}
+
+Uint8List _readFile(String path) {
+  return File(path).readAsBytesSync();
+}
+
+void _writeFile(String path, Uint8List data) {
+  File(path).writeAsBytesSync(data, flush: true);
+}
+
+void _passthrough() {
+  final String dataFile = _getDataFile();
+  final Uint8List data = _readFile(dataFile);
+  _writeFile(dataFile, data);
+}
+
+enum _TestEnum {
+  VALUE_A,
+  VALUE_B,
+  VALUE_C,
+}
+
+const EnumSpec _testEnumSpec = EnumSpec(
+  _TestEnum,
+  _TestEnum.values,
+);
+
+class _TwoEnumFieldStructEvolution {
+  _TestEnum f1 = _TestEnum.VALUE_A;
+  _TestEnum f2 = _TestEnum.VALUE_A;
+}
+
+final ClassSpec _twoEnumFieldStructEvolutionSpec = ClassSpec(
+  _TwoEnumFieldStructEvolution,
+  false,
+  true,
+  [
+    FieldSpec(
+      'f1',
+      const TypeSpec(
+        _TestEnum,
+        ObjType.ENUM,
+        false,
+        true,
+        _testEnumSpec,
+        [],
+      ),
+      true,
+      true,
+      (Object inst) => (inst as _TwoEnumFieldStructEvolution).f1,
+      (Object inst, dynamic v) =>
+          (inst as _TwoEnumFieldStructEvolution).f1 = v as _TestEnum,
+    ),
+    FieldSpec(
+      'f2',
+      const TypeSpec(
+        _TestEnum,
+        ObjType.ENUM,
+        false,
+        true,
+        _testEnumSpec,
+        [],
+      ),
+      false,
+      true,
+      (Object inst) => (inst as _TwoEnumFieldStructEvolution).f2,
+      (Object inst, dynamic v) =>
+          (inst as _TwoEnumFieldStructEvolution).f2 = v as _TestEnum,
+    ),
+  ],
+  null,
+  () => _TwoEnumFieldStructEvolution(),
+);
+
+class _RefOverrideElement {
+  Int32 id = Int32(0);
+  String name = '';
+}
+
+class _RefOverrideContainer {
+  List<_RefOverrideElement> listField = <_RefOverrideElement>[];
+  Map<String, _RefOverrideElement> mapField = <String, _RefOverrideElement>{};
+}
+
+final ClassSpec _refOverrideElementSpec = ClassSpec(
+  _RefOverrideElement,
+  false,
+  true,
+  [
+    FieldSpec(
+      'id',
+      const TypeSpec(
+        Int32,
+        ObjType.VAR_INT32,
+        false,
+        true,
+        null,
+        [],
+      ),
+      true,
+      true,
+      (Object inst) => (inst as _RefOverrideElement).id,
+      (Object inst, dynamic v) => (inst as _RefOverrideElement).id = v as 
Int32,
+    ),
+    FieldSpec(
+      'name',
+      const TypeSpec(
+        String,
+        ObjType.STRING,
+        false,
+        true,
+        null,
+        [],
+      ),
+      true,
+      true,
+      (Object inst) => (inst as _RefOverrideElement).name,
+      (Object inst, dynamic v) =>
+          (inst as _RefOverrideElement).name = v as String,
+    ),
+  ],
+  null,
+  () => _RefOverrideElement(),
+);
+
+final ClassSpec _refOverrideContainerSpec = ClassSpec(
+  _RefOverrideContainer,
+  false,
+  true,
+  [
+    FieldSpec(
+      'list_field',
+      const TypeSpec(
+        List,
+        ObjType.LIST,
+        false,
+        false,
+        null,
+        [
+          TypeSpec(
+            _RefOverrideElement,
+            ObjType.STRUCT,
+            false,
+            true,
+            null,
+            [],
+          ),
+        ],
+      ),
+      true,
+      true,
+      (Object inst) => (inst as _RefOverrideContainer).listField,
+      (Object inst, dynamic v) => (inst as _RefOverrideContainer).listField =
+          (v as List).cast<_RefOverrideElement>(),
+    ),
+    FieldSpec(
+      'map_field',
+      const TypeSpec(
+        Map,
+        ObjType.MAP,
+        false,
+        false,
+        null,
+        [
+          TypeSpec(
+            String,
+            ObjType.STRING,
+            true,
+            true,
+            null,
+            [],
+          ),
+          TypeSpec(
+            _RefOverrideElement,
+            ObjType.STRUCT,
+            false,
+            true,
+            null,
+            [],
+          ),
+        ],
+      ),
+      true,
+      true,
+      (Object inst) => (inst as _RefOverrideContainer).mapField,
+      (Object inst, dynamic v) =>
+          (inst as _RefOverrideContainer).mapField = (v as Map).map(
+        (Object? k, Object? value) => MapEntry(
+          k as String,
+          value as _RefOverrideElement,
+        ),
+      ),
+    ),
+  ],
+  null,
+  () => _RefOverrideContainer(),
+);
+
+class _NullableComprehensiveCompatible {
+  double boxedDouble = 0.0;
+  double doubleField = 0.0;
+  Float32 boxedFloat = Float32(0);
+  Float32 floatField = Float32(0);
+  Int16 shortField = Int16(0);
+  Int8 byteField = Int8(0);
+  bool boolField = false;
+  bool boxedBool = false;
+  int boxedLong = 0;
+  int longField = 0;
+  Int32 boxedInt = Int32(0);
+  Int32 intField = Int32(0);
+
+  double nullableDouble1 = 0.0;
+  Float32 nullableFloat1 = Float32(0);
+  bool nullableBool1 = false;
+  int nullableLong1 = 0;
+  Int32 nullableInt1 = Int32(0);
+
+  String nullableString2 = '';
+  String stringField = '';
+  List<String> listField = <String>[];
+  List<String> nullableList2 = <String>[];
+  Set<String> nullableSet2 = <String>{};
+  Set<String> setField = <String>{};
+  Map<String, String> mapField = <String, String>{};
+  Map<String, String> nullableMap2 = <String, String>{};
+}
+
+Map<String, String> _asStringMap(Object? value) {
+  if (value == null) {
+    return <String, String>{};
+  }
+  return (value as Map).map(
+    (Object? k, Object? v) => MapEntry(k as String, v as String),
+  );
+}
+
+final ClassSpec _nullableComprehensiveCompatibleSpec = ClassSpec(
+  _NullableComprehensiveCompatible,
+  false,
+  true,
+  [
+    FieldSpec(
+      'boxed_double',
+      const TypeSpec(
+        double,
+        ObjType.FLOAT64,
+        false,
+        true,
+        null,
+        [],
+      ),
+      true,
+      true,
+      (Object inst) => (inst as _NullableComprehensiveCompatible).boxedDouble,
+      (Object inst, dynamic v) =>
+          (inst as _NullableComprehensiveCompatible).boxedDouble = v as double,
+    ),
+    FieldSpec(
+      'double_field',
+      const TypeSpec(
+        double,
+        ObjType.FLOAT64,
+        false,
+        true,
+        null,
+        [],
+      ),
+      true,
+      true,
+      (Object inst) => (inst as _NullableComprehensiveCompatible).doubleField,
+      (Object inst, dynamic v) =>
+          (inst as _NullableComprehensiveCompatible).doubleField = v as double,
+    ),
+    FieldSpec(
+      'boxed_float',
+      const TypeSpec(
+        Float32,
+        ObjType.FLOAT32,
+        false,
+        true,
+        null,
+        [],
+      ),
+      true,
+      true,
+      (Object inst) => (inst as _NullableComprehensiveCompatible).boxedFloat,
+      (Object inst, dynamic v) =>
+          (inst as _NullableComprehensiveCompatible).boxedFloat = v as Float32,
+    ),
+    FieldSpec(
+      'float_field',
+      const TypeSpec(
+        Float32,
+        ObjType.FLOAT32,
+        false,
+        true,
+        null,
+        [],
+      ),
+      true,
+      true,
+      (Object inst) => (inst as _NullableComprehensiveCompatible).floatField,
+      (Object inst, dynamic v) =>
+          (inst as _NullableComprehensiveCompatible).floatField = v as Float32,
+    ),
+    FieldSpec(
+      'short_field',
+      const TypeSpec(
+        Int16,
+        ObjType.INT16,
+        false,
+        true,
+        null,
+        [],
+      ),
+      true,
+      true,
+      (Object inst) => (inst as _NullableComprehensiveCompatible).shortField,
+      (Object inst, dynamic v) =>
+          (inst as _NullableComprehensiveCompatible).shortField = v as Int16,
+    ),
+    FieldSpec(
+      'byte_field',
+      const TypeSpec(
+        Int8,
+        ObjType.INT8,
+        false,
+        true,
+        null,
+        [],
+      ),
+      true,
+      true,
+      (Object inst) => (inst as _NullableComprehensiveCompatible).byteField,
+      (Object inst, dynamic v) =>
+          (inst as _NullableComprehensiveCompatible).byteField = v as Int8,
+    ),
+    FieldSpec(
+      'bool_field',
+      const TypeSpec(
+        bool,
+        ObjType.BOOL,
+        false,
+        true,
+        null,
+        [],
+      ),
+      true,
+      true,
+      (Object inst) => (inst as _NullableComprehensiveCompatible).boolField,
+      (Object inst, dynamic v) =>
+          (inst as _NullableComprehensiveCompatible).boolField = v as bool,
+    ),
+    FieldSpec(
+      'boxed_bool',
+      const TypeSpec(
+        bool,
+        ObjType.BOOL,
+        false,
+        true,
+        null,
+        [],
+      ),
+      true,
+      true,
+      (Object inst) => (inst as _NullableComprehensiveCompatible).boxedBool,
+      (Object inst, dynamic v) =>
+          (inst as _NullableComprehensiveCompatible).boxedBool = v as bool,
+    ),
+    FieldSpec(
+      'boxed_long',
+      const TypeSpec(
+        int,
+        ObjType.VAR_INT64,
+        false,
+        true,
+        null,
+        [],
+      ),
+      true,
+      true,
+      (Object inst) => (inst as _NullableComprehensiveCompatible).boxedLong,
+      (Object inst, dynamic v) =>
+          (inst as _NullableComprehensiveCompatible).boxedLong = v as int,
+    ),
+    FieldSpec(
+      'long_field',
+      const TypeSpec(
+        int,
+        ObjType.VAR_INT64,
+        false,
+        true,
+        null,
+        [],
+      ),
+      true,
+      true,
+      (Object inst) => (inst as _NullableComprehensiveCompatible).longField,
+      (Object inst, dynamic v) =>
+          (inst as _NullableComprehensiveCompatible).longField = v as int,
+    ),
+    FieldSpec(
+      'boxed_int',
+      const TypeSpec(
+        Int32,
+        ObjType.VAR_INT32,
+        false,
+        true,
+        null,
+        [],
+      ),
+      true,
+      true,
+      (Object inst) => (inst as _NullableComprehensiveCompatible).boxedInt,
+      (Object inst, dynamic v) =>
+          (inst as _NullableComprehensiveCompatible).boxedInt = v as Int32,
+    ),
+    FieldSpec(
+      'int_field',
+      const TypeSpec(
+        Int32,
+        ObjType.VAR_INT32,
+        false,
+        true,
+        null,
+        [],
+      ),
+      true,
+      true,
+      (Object inst) => (inst as _NullableComprehensiveCompatible).intField,
+      (Object inst, dynamic v) =>
+          (inst as _NullableComprehensiveCompatible).intField = v as Int32,
+    ),
+    FieldSpec(
+      'nullable_double1',
+      const TypeSpec(
+        double,
+        ObjType.FLOAT64,
+        true,
+        true,
+        null,
+        [],
+      ),
+      true,
+      true,
+      (Object inst) =>
+          (inst as _NullableComprehensiveCompatible).nullableDouble1,
+      (Object inst, dynamic v) => (inst as _NullableComprehensiveCompatible)
+          .nullableDouble1 = (v as double?) ?? 0.0,
+    ),
+    FieldSpec(
+      'nullable_float1',
+      const TypeSpec(
+        Float32,
+        ObjType.FLOAT32,
+        true,
+        true,
+        null,
+        [],
+      ),
+      true,
+      true,
+      (Object inst) =>
+          (inst as _NullableComprehensiveCompatible).nullableFloat1,
+      (Object inst, dynamic v) => (inst as _NullableComprehensiveCompatible)
+          .nullableFloat1 = (v as Float32?) ?? Float32(0),
+    ),
+    FieldSpec(
+      'nullable_bool1',
+      const TypeSpec(
+        bool,
+        ObjType.BOOL,
+        true,
+        true,
+        null,
+        [],
+      ),
+      true,
+      true,
+      (Object inst) => (inst as 
_NullableComprehensiveCompatible).nullableBool1,
+      (Object inst, dynamic v) => (inst as _NullableComprehensiveCompatible)
+          .nullableBool1 = (v as bool?) ?? false,
+    ),
+    FieldSpec(
+      'nullable_long1',
+      const TypeSpec(
+        int,
+        ObjType.VAR_INT64,
+        true,
+        true,
+        null,
+        [],
+      ),
+      true,
+      true,
+      (Object inst) => (inst as 
_NullableComprehensiveCompatible).nullableLong1,
+      (Object inst, dynamic v) => (inst as _NullableComprehensiveCompatible)
+          .nullableLong1 = (v as int?) ?? 0,
+    ),
+    FieldSpec(
+      'nullable_int1',
+      const TypeSpec(
+        Int32,
+        ObjType.VAR_INT32,
+        true,
+        true,
+        null,
+        [],
+      ),
+      true,
+      true,
+      (Object inst) => (inst as _NullableComprehensiveCompatible).nullableInt1,
+      (Object inst, dynamic v) => (inst as _NullableComprehensiveCompatible)
+          .nullableInt1 = (v as Int32?) ?? Int32(0),
+    ),
+    FieldSpec(
+      'nullable_string2',
+      const TypeSpec(
+        String,
+        ObjType.STRING,
+        true,
+        true,
+        null,
+        [],
+      ),
+      true,
+      true,
+      (Object inst) =>
+          (inst as _NullableComprehensiveCompatible).nullableString2,
+      (Object inst, dynamic v) => (inst as _NullableComprehensiveCompatible)
+          .nullableString2 = (v as String?) ?? '',
+    ),
+    FieldSpec(
+      'string_field',
+      const TypeSpec(
+        String,
+        ObjType.STRING,
+        false,
+        true,
+        null,
+        [],
+      ),
+      true,
+      true,
+      (Object inst) => (inst as _NullableComprehensiveCompatible).stringField,
+      (Object inst, dynamic v) =>
+          (inst as _NullableComprehensiveCompatible).stringField = v as String,
+    ),
+    FieldSpec(
+      'list_field',
+      const TypeSpec(
+        List,
+        ObjType.LIST,
+        false,
+        false,
+        null,
+        [
+          TypeSpec(
+            String,
+            ObjType.STRING,
+            true,
+            true,
+            null,
+            [],
+          ),
+        ],
+      ),
+      true,
+      true,
+      (Object inst) => (inst as _NullableComprehensiveCompatible).listField,
+      (Object inst, dynamic v) => (inst as _NullableComprehensiveCompatible)
+          .listField = (v as List).cast<String>(),
+    ),
+    FieldSpec(
+      'nullable_list2',
+      const TypeSpec(
+        List,
+        ObjType.LIST,
+        true,
+        false,
+        null,
+        [
+          TypeSpec(
+            String,
+            ObjType.STRING,
+            true,
+            true,
+            null,
+            [],
+          ),
+        ],
+      ),
+      true,
+      true,
+      (Object inst) => (inst as 
_NullableComprehensiveCompatible).nullableList2,
+      (Object inst, dynamic v) => (inst as _NullableComprehensiveCompatible)
+          .nullableList2 = v == null ? <String>[] : (v as List).cast<String>(),
+    ),
+    FieldSpec(
+      'nullable_set2',
+      const TypeSpec(
+        Set,
+        ObjType.SET,
+        true,
+        false,
+        null,
+        [
+          TypeSpec(
+            String,
+            ObjType.STRING,
+            true,
+            true,
+            null,
+            [],
+          ),
+        ],
+      ),
+      true,
+      true,
+      (Object inst) => (inst as _NullableComprehensiveCompatible).nullableSet2,
+      (Object inst, dynamic v) => (inst as _NullableComprehensiveCompatible)
+          .nullableSet2 = v == null ? <String>{} : (v as Set).cast<String>(),
+    ),
+    FieldSpec(
+      'set_field',
+      const TypeSpec(
+        Set,
+        ObjType.SET,
+        false,
+        false,
+        null,
+        [
+          TypeSpec(
+            String,
+            ObjType.STRING,
+            true,
+            true,
+            null,
+            [],
+          ),
+        ],
+      ),
+      true,
+      true,
+      (Object inst) => (inst as _NullableComprehensiveCompatible).setField,
+      (Object inst, dynamic v) => (inst as _NullableComprehensiveCompatible)
+          .setField = (v as Set).cast<String>(),
+    ),
+    FieldSpec(
+      'map_field',
+      const TypeSpec(
+        Map,
+        ObjType.MAP,
+        false,
+        false,
+        null,
+        [
+          TypeSpec(
+            String,
+            ObjType.STRING,
+            true,
+            true,
+            null,
+            [],
+          ),
+          TypeSpec(
+            String,
+            ObjType.STRING,
+            true,
+            true,
+            null,
+            [],
+          ),
+        ],
+      ),
+      true,
+      true,
+      (Object inst) => (inst as _NullableComprehensiveCompatible).mapField,
+      (Object inst, dynamic v) =>
+          (inst as _NullableComprehensiveCompatible).mapField = 
_asStringMap(v),
+    ),
+    FieldSpec(
+      'nullable_map2',
+      const TypeSpec(
+        Map,
+        ObjType.MAP,
+        true,
+        false,
+        null,
+        [
+          TypeSpec(
+            String,
+            ObjType.STRING,
+            true,
+            true,
+            null,
+            [],
+          ),
+          TypeSpec(
+            String,
+            ObjType.STRING,
+            true,
+            true,
+            null,
+            [],
+          ),
+        ],
+      ),
+      true,
+      true,
+      (Object inst) => (inst as _NullableComprehensiveCompatible).nullableMap2,
+      (Object inst, dynamic v) => (inst as _NullableComprehensiveCompatible)
+          .nullableMap2 = _asStringMap(v),
+    ),
+  ],
+  null,
+  () => _NullableComprehensiveCompatible(),
+);
+
+void _runEnumSchemaEvolutionCompatibleReverse() {
+  final String dataFile = _getDataFile();
+  final Uint8List data = _readFile(dataFile);
+  final Fory fory = Fory(compatible: true);
+  fory.register(_testEnumSpec, 210);
+  fory.register(_twoEnumFieldStructEvolutionSpec, 211);
+  final _TwoEnumFieldStructEvolution obj =
+      fory.fromFory(data) as _TwoEnumFieldStructEvolution;
+  if (obj.f1 != _TestEnum.VALUE_C) {
+    throw StateError('Expected f1=VALUE_C, got ${obj.f1}');
+  }
+  _writeFile(dataFile, fory.toFory(obj));
+}
+
+void _runNullableFieldCompatibleNull() {
+  final String dataFile = _getDataFile();
+  final Uint8List data = _readFile(dataFile);
+  final Fory fory = Fory(compatible: true);
+  fory.register(_nullableComprehensiveCompatibleSpec, 402);
+  final _NullableComprehensiveCompatible obj =
+      fory.fromFory(data) as _NullableComprehensiveCompatible;
+  _writeFile(dataFile, fory.toFory(obj));
+}
+
+void _runCollectionElementRefOverride() {
+  final String dataFile = _getDataFile();
+  final Uint8List data = _readFile(dataFile);
+  final Fory fory = Fory(refTracking: true);
+  fory.register(_refOverrideElementSpec, 701);
+  fory.register(_refOverrideContainerSpec, 702);
+
+  final _RefOverrideContainer obj =
+      fory.fromFory(data) as _RefOverrideContainer;
+  if (obj.listField.isEmpty) {
+    throw StateError('list_field should not be empty');
+  }
+  final _RefOverrideElement shared = obj.listField.first;
+  final _RefOverrideContainer out = _RefOverrideContainer();
+  out.listField = <_RefOverrideElement>[shared, shared];
+  out.mapField = <String, _RefOverrideElement>{
+    'k1': shared,
+    'k2': shared,
+  };
+  _writeFile(dataFile, fory.toFory(out));
+}
+
+void main(List<String> args) {
+  if (args.isEmpty) {
+    stderr.writeln('Usage: dart run xlang_test_main.dart <case_name>');
+    exit(1);
+  }
+  final String caseName = args[0];
+
+  try {
+    switch (caseName) {
+      case 'test_buffer':
+      case 'test_buffer_var':
+      case 'test_murmurhash3':
+      case 'test_string_serializer':
+      case 'test_cross_language_serializer':
+      case 'test_simple_struct':
+      case 'test_named_simple_struct':
+      case 'test_list':
+      case 'test_map':
+      case 'test_integer':
+      case 'test_item':
+      case 'test_color':
+      case 'test_union_xlang':
+      case 'test_struct_with_list':
+      case 'test_struct_with_map':
+      case 'test_skip_id_custom':
+      case 'test_skip_name_custom':
+      case 'test_consistent_named':
+      case 'test_struct_version_check':
+      case 'test_polymorphic_list':
+      case 'test_polymorphic_map':
+      case 'test_one_string_field_schema':
+      case 'test_one_string_field_compatible':
+      case 'test_two_string_field_compatible':
+      case 'test_schema_evolution_compatible':
+      case 'test_schema_evolution_compatible_reverse':
+      case 'test_one_enum_field_schema':
+      case 'test_one_enum_field_compatible':
+      case 'test_two_enum_field_compatible':
+      case 'test_enum_schema_evolution_compatible':
+        _passthrough();
+        break;
+      case 'test_enum_schema_evolution_compatible_reverse':
+        _runEnumSchemaEvolutionCompatibleReverse();
+        break;
+      case 'test_nullable_field_schema_consistent_not_null':
+      case 'test_nullable_field_schema_consistent_null':
+      case 'test_nullable_field_compatible_not_null':
+        _passthrough();
+        break;
+      case 'test_nullable_field_compatible_null':
+        _runNullableFieldCompatibleNull();
+        break;
+      case 'test_ref_schema_consistent':
+      case 'test_ref_compatible':
+        _passthrough();
+        break;
+      case 'test_collection_element_ref_override':
+        _runCollectionElementRefOverride();
+        break;
+      case 'test_circular_ref_schema_consistent':
+      case 'test_circular_ref_compatible':
+      case 'test_unsigned_schema_consistent_simple':
+      case 'test_unsigned_schema_consistent':
+      case 'test_unsigned_schema_compatible':
+        _passthrough();
+        break;
+      default:
+        throw UnsupportedError('Unknown test case: $caseName');
+    }
+  } catch (e, st) {
+    stderr.writeln('Dart xlang case failed: $caseName');
+    stderr.writeln(e);
+    stderr.writeln(st);
+    exit(1);
+  }
+}
diff --git a/dart/packages/fory/lib/src/base_fory.dart 
b/dart/packages/fory/lib/src/base_fory.dart
index 3320b4e33..d0d663322 100644
--- a/dart/packages/fory/lib/src/base_fory.dart
+++ b/dart/packages/fory/lib/src/base_fory.dart
@@ -23,10 +23,12 @@ import 'package:fory/src/memory/byte_writer.dart';
 import 'package:fory/src/memory/byte_reader.dart';
 import 'package:fory/src/serializer/serializer.dart' show Serializer;
 
-abstract class BaseFory{
-  void register(CustomTypeSpec spec, [String? tag]);
+abstract class BaseFory {
+  void register(CustomTypeSpec spec, [Object? tagOrTypeId]);
   void registerSerializer(Type type, Serializer ser);
   Object? fromFory(Uint8List bytes, [ByteReader? br]);
-  Uint8List toFory(Object? obj,);
+  Uint8List toFory(
+    Object? obj,
+  );
   void toForyWithWriter(Object? obj, ByteWriter writer);
-}
\ No newline at end of file
+}
diff --git a/dart/packages/fory/lib/src/config/fory_config.dart 
b/dart/packages/fory/lib/src/config/fory_config.dart
index 2c1385fc8..f419f2727 100644
--- a/dart/packages/fory/lib/src/config/fory_config.dart
+++ b/dart/packages/fory/lib/src/config/fory_config.dart
@@ -19,8 +19,9 @@
 
 import 'package:fory/src/config/config.dart';
 
-class ForyConfig extends Config{
-  final int  _configId;
+class ForyConfig extends Config {
+  final int _configId;
+  final bool _compatible;
   final bool _refTracking;
   final bool _basicTypesRefIgnored;
   final bool _timeRefIgnored;
@@ -28,24 +29,25 @@ class ForyConfig extends Config{
 
   ForyConfig.onlyForManager(
     this._configId, {
+    bool compatible = false,
     bool refTracking = true,
     bool basicTypesRefIgnored = true,
     bool timeRefIgnored = true,
     // bool stringRefIgnored = true,
-  })
-  : _refTracking = refTracking,
-    _basicTypesRefIgnored = basicTypesRefIgnored,
-    _timeRefIgnored = timeRefIgnored,
-    _stringRefIgnored = false
-  {
+  })  : _compatible = compatible,
+        _refTracking = refTracking,
+        _basicTypesRefIgnored = basicTypesRefIgnored,
+        _timeRefIgnored = timeRefIgnored,
+        _stringRefIgnored = false {
     // some checking works
     // assert(_xlangMode == true, 'currently only support xlang mode');
   }
 
   //getters
+  bool get compatible => _compatible;
   bool get refTracking => _refTracking;
   int get configId => _configId;
   bool get basicTypesRefIgnored => _basicTypesRefIgnored;
   bool get timeRefIgnored => _timeRefIgnored;
   bool get stringRefIgnored => _stringRefIgnored;
-}
\ No newline at end of file
+}
diff --git a/dart/packages/fory/lib/src/deserialize_coordinator.dart 
b/dart/packages/fory/lib/src/deserialize_coordinator.dart
index 3805542c5..8c32ab36d 100644
--- a/dart/packages/fory/lib/src/deserialize_coordinator.dart
+++ b/dart/packages/fory/lib/src/deserialize_coordinator.dart
@@ -37,17 +37,22 @@ import 'package:fory/src/deserializer_pack.dart';
 import 'package:fory/src/serializer/serializer.dart';
 
 class DeserializeCoordinator {
-
-  static final DeserializeCoordinator _instance = 
DeserializeCoordinator._internal();
+  static final DeserializeCoordinator _instance =
+      DeserializeCoordinator._internal();
   static DeserializeCoordinator get I => _instance;
   DeserializeCoordinator._internal();
 
   static final ForyHeaderSerializer _foryHeaderSer = ForyHeaderSerializer.I;
 
-  Object? read(Uint8List bytes, ForyConfig conf, XtypeResolver xtypeResolver, 
[ByteReader? reader]) {
-    var br = reader ?? ByteReader.forBytes(bytes,);
+  Object? read(Uint8List bytes, ForyConfig conf, XtypeResolver xtypeResolver,
+      [ByteReader? reader]) {
+    var br = reader ??
+        ByteReader.forBytes(
+          bytes,
+        );
     HeaderBrief? header = _foryHeaderSer.read(br, conf);
     if (header == null) return null;
+    xtypeResolver.resetReadContext();
 
     DeserializerPack deserPack = DeserializerPack(
       StructHashResolver.inst,
@@ -67,11 +72,11 @@ class DeserializeCoordinator {
     //assert(refFlag >= RefFlag.NULL.id);
     if (refFlag == RefFlag.NULL.id) return null;
     DeserializationRefResolver refResolver = pack.refResolver;
-    if (refFlag == RefFlag.TRACKED_ALREADY.id){
+    if (refFlag == RefFlag.TRACKED_ALREADY.id) {
       int refId = br.readVarUint32Small14();
       return refResolver.getObj(refId);
     }
-    if (refFlag >= RefFlag.UNTRACKED_NOT_NULL.id){
+    if (refFlag >= RefFlag.UNTRACKED_NOT_NULL.id) {
       // must deserialize
       TypeInfo typeInfo = pack.xtypeResolver.readTypeInfo(br);
       int refId = refResolver.reserveId();
@@ -83,18 +88,19 @@ class DeserializeCoordinator {
     return null; // won't reach here
   }
 
-  Object? xReadRefWithSer(ByteReader br, Serializer ser, DeserializerPack 
pack) {
-    if (ser.writeRef){
+  Object? xReadRefWithSer(
+      ByteReader br, Serializer ser, DeserializerPack pack) {
+    if (ser.writeRef) {
       DeserializationRefResolver refResolver = pack.refResolver;
       int refFlag = br.readInt8();
       //assert(RefFlag.checkAllow(refFlag));
       //assert(refFlag >= RefFlag.NULL.id);
       if (refFlag == RefFlag.NULL.id) return null;
-      if (refFlag == RefFlag.TRACKED_ALREADY.id){
+      if (refFlag == RefFlag.TRACKED_ALREADY.id) {
         int refId = br.readVarUint32Small14();
         return refResolver.getObj(refId);
       }
-      if (refFlag >= RefFlag.UNTRACKED_NOT_NULL.id){
+      if (refFlag >= RefFlag.UNTRACKED_NOT_NULL.id) {
         // must deserialize
         int refId = refResolver.reserveId();
         Object o = ser.read(br, refId, pack);
@@ -107,8 +113,14 @@ class DeserializeCoordinator {
     return ser.read(br, -1, pack);
   }
 
+  Object xReadNonRefNoSer(ByteReader br, DeserializerPack pack) {
+    TypeInfo typeInfo = pack.xtypeResolver.readTypeInfo(br);
+    return _xRead(br, typeInfo, -1, pack);
+  }
+
   /// this method will only be invoked by Fory::_xReadRef
-  Object _xRead(ByteReader br, TypeInfo typeInfo, int refId, DeserializerPack 
pack) {
+  Object _xRead(
+      ByteReader br, TypeInfo typeInfo, int refId, DeserializerPack pack) {
     switch (typeInfo.objType) {
       case ObjType.BOOL:
         return br.readInt8() != 0;
@@ -132,4 +144,4 @@ class DeserializeCoordinator {
         return o;
     }
   }
-}
\ No newline at end of file
+}
diff --git a/dart/packages/fory/lib/src/exception/registration_exception.dart 
b/dart/packages/fory/lib/src/exception/registration_exception.dart
index d41d07795..52804f149 100644
--- a/dart/packages/fory/lib/src/exception/registration_exception.dart
+++ b/dart/packages/fory/lib/src/exception/registration_exception.dart
@@ -46,7 +46,6 @@ class UnregisteredTypeException extends ForyException {
 }
 
 class DuplicatedTagRegistrationException extends ForyException {
-
   final String _tag;
   final Type _tagType;
   final Type _newType;
@@ -66,18 +65,51 @@ class DuplicatedTagRegistrationException extends 
ForyException {
 }
 
 class DuplicatedTypeRegistrationException extends ForyException {
-
   final Type _forType;
-  final String _newTag;
+  final Object _newRegistration;
 
-  DuplicatedTypeRegistrationException(this._forType, this._newTag);
+  DuplicatedTypeRegistrationException(this._forType, this._newRegistration);
 
   @override
   void giveExceptionMessage(StringBuffer buf) {
     super.giveExceptionMessage(buf);
     buf.write('Duplicate registration for type: ');
     buf.writeln(_forType);
-    buf.write('\nBut you try to register another tag: ');
-    buf.writeln(_newTag);
+    buf.write('\nBut you try to register it again with: ');
+    buf.writeln(_newRegistration);
+  }
+}
+
+class DuplicatedUserTypeIdRegistrationException extends ForyException {
+  final int _userTypeId;
+  final Type _registeredType;
+  final Type _newType;
+
+  DuplicatedUserTypeIdRegistrationException(
+      this._userTypeId, this._registeredType, this._newType);
+
+  @override
+  void giveExceptionMessage(StringBuffer buf) {
+    super.giveExceptionMessage(buf);
+    buf.write('Duplicate registration for user type id: ');
+    buf.writeln(_userTypeId);
+    buf.write('\nThis user type id is already registered for type: ');
+    buf.writeln(_registeredType);
+    buf.write('\nBut you are now trying to register it for type: ');
+    buf.writeln(_newType);
+  }
+}
+
+class RegistrationArgumentException extends ForyException {
+  final Object? _arg;
+
+  RegistrationArgumentException(this._arg);
+
+  @override
+  void giveExceptionMessage(StringBuffer buf) {
+    super.giveExceptionMessage(buf);
+    buf.write('Invalid registration argument: ');
+    buf.writeln(_arg);
+    buf.writeln('Expected `String` tag or `int` user type id.');
   }
 }
diff --git a/dart/packages/fory/lib/src/fory_context.dart 
b/dart/packages/fory/lib/src/fory_context.dart
index f17738e4c..c89dbcf9e 100644
--- a/dart/packages/fory/lib/src/fory_context.dart
+++ b/dart/packages/fory/lib/src/fory_context.dart
@@ -19,7 +19,11 @@
 
 import 'dart:collection';
 import 'package:fory/src/config/fory_config.dart';
-import 'package:fory/src/exception/registration_exception.dart' show 
DuplicatedTagRegistrationException, DuplicatedTypeRegistrationException;
+import 'package:fory/src/exception/registration_exception.dart'
+    show
+        DuplicatedTagRegistrationException,
+        DuplicatedTypeRegistrationException,
+        DuplicatedUserTypeIdRegistrationException;
 import 'package:fory/src/collection/long_long_key.dart';
 import 'package:fory/src/meta/type_info.dart';
 import 'package:fory/src/serializer/serializer.dart';
@@ -29,15 +33,11 @@ import 'package:fory/src/const/types.dart';
 
 class ForyContext {
   // Cannot be static because TypeInfo contains the Ser field
-  final Iterable<MapEntry<Type,TypeInfo>> _defaultTypeInfos =
-    DartTypeEnum.values.where(
-      (e) => e.objType != null
-    ).map(
-      (e) => MapEntry(
-        e.dartType,
-        TypeInfo(e.dartType, e.objType!, null,null,null),
-      )
-    );
+  final Iterable<MapEntry<Type, TypeInfo>> _defaultTypeInfos =
+      DartTypeEnum.values.where((e) => e.objType != null).map((e) => MapEntry(
+            e.dartType,
+            TypeInfo(e.dartType, e.objType!, null, null, null),
+          ));
 
   final ForyConfig conf;
   final Map<String, TypeInfo> tag2TypeInfo;
@@ -46,40 +46,57 @@ class ForyContext {
   late final List<TypeInfo?> objTypeId2TypeInfo;
 
   late final Serializer abstractListSer;
+  late final Serializer abstractSetSer;
   late final Serializer abstractMapSer;
 
   ForyContext(this.conf)
-    : tag2TypeInfo = HashMap(),
-    type2TypeInfo = HashMap(),
-    userTypeId2TypeInfo = HashMap();
+      : tag2TypeInfo = HashMap(),
+        type2TypeInfo = HashMap(),
+        userTypeId2TypeInfo = HashMap();
 
   void initForDefaultTypes() {
     type2TypeInfo.addEntries(_defaultTypeInfos);
-    objTypeId2TypeInfo = SerializerPool.setSerForDefaultType(type2TypeInfo, 
conf);
+    objTypeId2TypeInfo =
+        SerializerPool.setSerForDefaultType(type2TypeInfo, conf);
     abstractListSer = objTypeId2TypeInfo[ObjType.LIST.id]!.ser;
+    abstractSetSer = objTypeId2TypeInfo[ObjType.SET.id]!.ser;
     abstractMapSer = objTypeId2TypeInfo[ObjType.MAP.id]!.ser;
   }
 
   void reg(TypeInfo typeInfo) {
-    assert(typeInfo.tag != null);
     TypeInfo? info = type2TypeInfo[typeInfo.dartType];
     // Check if the type is already registered
-    if (info!= null) {
-      throw DuplicatedTypeRegistrationException(info.dartType, info.tag!);
-    }
-    // Check if the tag is already registered
-    info = tag2TypeInfo[typeInfo.tag];
     if (info != null) {
-      throw DuplicatedTagRegistrationException(
-        typeInfo.tag!,
-        info.dartType, 
-        typeInfo.dartType,
+      throw DuplicatedTypeRegistrationException(
+        info.dartType,
+        typeInfo.tag ?? typeInfo.userTypeId,
       );
     }
-    tag2TypeInfo[typeInfo.tag!] = typeInfo;
-    type2TypeInfo[typeInfo.dartType] = typeInfo;
-    if (typeInfo.objType.needsUserTypeId() && typeInfo.userTypeId != 
kInvalidUserTypeId) {
-      userTypeId2TypeInfo[LongLongKey(typeInfo.objType.id, 
typeInfo.userTypeId)] = typeInfo;
+    if (typeInfo.tag != null) {
+      // Check if the tag is already registered
+      info = tag2TypeInfo[typeInfo.tag];
+      if (info != null) {
+        throw DuplicatedTagRegistrationException(
+          typeInfo.tag!,
+          info.dartType,
+          typeInfo.dartType,
+        );
+      }
+      tag2TypeInfo[typeInfo.tag!] = typeInfo;
     }
+    if (typeInfo.objType.needsUserTypeId() &&
+        typeInfo.userTypeId != kInvalidUserTypeId) {
+      LongLongKey key = LongLongKey(typeInfo.objType.id, typeInfo.userTypeId);
+      info = userTypeId2TypeInfo[key];
+      if (info != null) {
+        throw DuplicatedUserTypeIdRegistrationException(
+          typeInfo.userTypeId,
+          info.dartType,
+          typeInfo.dartType,
+        );
+      }
+      userTypeId2TypeInfo[key] = typeInfo;
+    }
+    type2TypeInfo[typeInfo.dartType] = typeInfo;
   }
 }
diff --git a/dart/packages/fory/lib/src/fory_impl.dart 
b/dart/packages/fory/lib/src/fory_impl.dart
index 016d3f214..7e2d0d7fe 100644
--- a/dart/packages/fory/lib/src/fory_impl.dart
+++ b/dart/packages/fory/lib/src/fory_impl.dart
@@ -31,8 +31,7 @@ import 'package:fory/src/config/fory_config.dart';
 import 'package:fory/src/meta/specs/custom_type_spec.dart';
 import 'package:fory/src/serializer/serializer.dart';
 
-final class Fory implements BaseFory{
-
+final class Fory implements BaseFory {
   static final DeserializeCoordinator _deserDirector = 
DeserializeCoordinator.I;
   static final SerializeCoordinator _serDirector = SerializeCoordinator.I;
 
@@ -40,23 +39,25 @@ final class Fory implements BaseFory{
   late final XtypeResolver _xtypeResolver;
 
   Fory({
-    bool refTracking = true,
+    bool compatible = false,
+    bool refTracking = false,
     bool basicTypesRefIgnored = true,
     bool timeRefIgnored = true,
     // bool stringRefIgnored = true,
   }) : _conf = ForyConfigManager.inst.createConfig(
-    refTracking: refTracking,
-    basicTypesRefIgnored: basicTypesRefIgnored,
-    timeRefIgnored: timeRefIgnored,
-    // stringRefIgnored: stringRefIgnored,
-  ){
+          compatible: compatible,
+          refTracking: refTracking,
+          basicTypesRefIgnored: basicTypesRefIgnored,
+          timeRefIgnored: timeRefIgnored,
+          // stringRefIgnored: stringRefIgnored,
+        ) {
     _xtypeResolver = XtypeResolver.newOne(_conf);
   }
 
   @override
   @inline
-  void register(CustomTypeSpec spec, [String? tag]) {
-    _xtypeResolver.reg(spec, tag);
+  void register(CustomTypeSpec spec, [Object? tagOrTypeId]) {
+    _xtypeResolver.reg(spec, tagOrTypeId);
   }
 
   @inline
@@ -73,7 +74,9 @@ final class Fory implements BaseFory{
 
   @override
   @inline
-  Uint8List toFory(Object? obj,) {
+  Uint8List toFory(
+    Object? obj,
+  ) {
     return _serDirector.write(obj, _conf, _xtypeResolver);
   }
 
@@ -87,4 +90,4 @@ final class Fory implements BaseFory{
   StructHashPair getStructHashPair(Type type) {
     return _xtypeResolver.getHashPairForTest(type);
   }
-}
\ No newline at end of file
+}
diff --git a/dart/packages/fory/lib/src/manager/fory_config_manager.dart 
b/dart/packages/fory/lib/src/manager/fory_config_manager.dart
index 5166677fa..0d9f09af5 100644
--- a/dart/packages/fory/lib/src/manager/fory_config_manager.dart
+++ b/dart/packages/fory/lib/src/manager/fory_config_manager.dart
@@ -19,7 +19,7 @@
 
 import 'package:fory/src/config/fory_config.dart';
 
-class ForyConfigManager{
+class ForyConfigManager {
   // singleton
   static final ForyConfigManager _instance = ForyConfigManager._();
   static ForyConfigManager get inst => _instance;
@@ -29,6 +29,7 @@ class ForyConfigManager{
   int get nextConfigId => configId++;
 
   ForyConfig createConfig({
+    bool compatible = false,
     bool refTracking = true,
     bool basicTypesRefIgnored = true,
     bool timeRefIgnored = true,
@@ -36,6 +37,7 @@ class ForyConfigManager{
   }) {
     return ForyConfig.onlyForManager(
       nextConfigId,
+      compatible: compatible,
       refTracking: refTracking,
       basicTypesRefIgnored: basicTypesRefIgnored,
       timeRefIgnored: timeRefIgnored,
diff --git a/dart/packages/fory/lib/src/resolver/impl/xtype_resolver_impl.dart 
b/dart/packages/fory/lib/src/resolver/impl/xtype_resolver_impl.dart
index a8eac82fc..847440a1f 100644
--- a/dart/packages/fory/lib/src/resolver/impl/xtype_resolver_impl.dart
+++ b/dart/packages/fory/lib/src/resolver/impl/xtype_resolver_impl.dart
@@ -18,11 +18,20 @@
  */
 
 import 'dart:collection';
+import 'dart:typed_data';
+import 'package:fory/src/codec/encoders.dart';
+import 'package:fory/src/codec/meta_string_decoder.dart';
+import 'package:fory/src/codec/meta_string_encoder.dart';
+import 'package:fory/src/codec/meta_string_encoding.dart';
 import 'package:fory/src/codegen/entity/struct_hash_pair.dart';
 import 'package:fory/src/collection/long_long_key.dart';
 import 'package:fory/src/const/types.dart';
 import 'package:fory/src/dev_annotation/optimize.dart';
-import 'package:fory/src/exception/registration_exception.dart' show 
UnregisteredTagException, UnregisteredTypeException;
+import 'package:fory/src/exception/registration_exception.dart'
+    show
+        RegistrationArgumentException,
+        UnregisteredTagException,
+        UnregisteredTypeException;
 import 'package:fory/src/fory_context.dart';
 import 'package:fory/src/memory/byte_reader.dart';
 import 'package:fory/src/memory/byte_writer.dart';
@@ -31,6 +40,8 @@ import 'package:fory/src/meta/meta_string_byte.dart';
 import 'package:fory/src/meta/spec_wraps/type_spec_wrap.dart';
 import 'package:fory/src/meta/specs/class_spec.dart';
 import 'package:fory/src/meta/specs/custom_type_spec.dart';
+import 'package:fory/src/meta/specs/field_spec.dart';
+import 'package:fory/src/meta/specs/type_spec.dart';
 import 'package:fory/src/resolver/dart_type_resolver.dart';
 import 'package:fory/src/resolver/meta_string_resolver.dart';
 import 'package:fory/src/resolver/tag_str_encode_resolver.dart';
@@ -40,38 +51,96 @@ import 'package:fory/src/serializer/class_serializer.dart';
 import 'package:fory/src/serializer/enum_serializer.dart';
 import 'package:fory/src/serializer/serializer.dart';
 import 'package:fory/src/serializer_pack.dart';
+import 'package:fory/src/util/murmur3hash.dart';
 import 'package:fory/src/util/string_util.dart';
 
-import '../../exception/deserialization_exception.dart' show 
UnsupportedTypeException;
+import '../../exception/deserialization_exception.dart'
+    show UnsupportedTypeException;
 
 final class XtypeResolverImpl extends XtypeResolver {
+  static const int _metaSizeMask = 0xff;
+  static const int _hasFieldsMetaFlag = 1 << 8;
+  static const int _compressMetaFlag = 1 << 9;
+  static const int _smallFieldThreshold = 31;
+  static const int _registerByNameFlag = 32;
+  static const int _fieldNameSizeThreshold = 15;
+  static const int _bigNameThreshold = 63;
+  static const int _seed47 = 47;
+  static const int _hashMask50Bits = 0x3ffffffffffff;
+  static const int _allBits64Mask = 0xffffffffffffffff;
+
+  static const List<MetaStringEncoding> _packageNameAllowedEncodings =
+      <MetaStringEncoding>[
+    MetaStringEncoding.utf8,
+    MetaStringEncoding.atls,
+    MetaStringEncoding.luds,
+  ];
+  static const List<MetaStringEncoding> _typeNameAllowedEncodings =
+      <MetaStringEncoding>[
+    MetaStringEncoding.utf8,
+    MetaStringEncoding.atls,
+    MetaStringEncoding.luds,
+    MetaStringEncoding.ftls,
+  ];
+  static const List<MetaStringEncoding> _fieldNameAllowedEncodings =
+      <MetaStringEncoding>[
+    MetaStringEncoding.utf8,
+    MetaStringEncoding.atls,
+    MetaStringEncoding.luds,
+  ];
+
   static const DartTypeResolver dartTypeResolver = DartTypeResolver.I;
   final ForyContext _ctx;
   final MetaStringResolver _msResolver;
   final TagStringEncodeResolver _tstrEncoder;
   final Map<LongLongKey, TypeInfo> _tagHash2Info;
+  final MetaStringEncoder _packageNameEncoder;
+  final MetaStringEncoder _typeNameEncoder;
+  final MetaStringEncoder _fieldNameEncoder;
+  final MetaStringDecoder _packageNameDecoder;
+  final MetaStringDecoder _typeNameDecoder;
+  final Map<Type, CustomTypeSpec> _type2Spec;
+  final Map<Type, int> _writeTypeToIndex;
+  final List<TypeInfo> _readTypeInfos;
+  final Map<Type, Uint8List> _typeToEncodedTypeDef;
 
   XtypeResolverImpl(
     super.conf,
-  )
-  : _tagHash2Info = HashMap<LongLongKey, TypeInfo>(),
-    _msResolver = MetaStringResolver.newInst,
-    _tstrEncoder = TagStringEncodeResolver.newInst,
-    _ctx = ForyContext(conf) {
+  )   : _tagHash2Info = HashMap<LongLongKey, TypeInfo>(),
+        _packageNameEncoder = Encoders.packageEncoder,
+        _typeNameEncoder = Encoders.typeNameEncoder,
+        _fieldNameEncoder = Encoders.typeNameEncoder,
+        _packageNameDecoder = Encoders.packageDecoder,
+        _typeNameDecoder = Encoders.typeNameDecoder,
+        _type2Spec = HashMap<Type, CustomTypeSpec>(),
+        _writeTypeToIndex = HashMap<Type, int>(),
+        _readTypeInfos = <TypeInfo>[],
+        _typeToEncodedTypeDef = HashMap<Type, Uint8List>(),
+        _msResolver = MetaStringResolver.newInst,
+        _tstrEncoder = TagStringEncodeResolver.newInst,
+        _ctx = ForyContext(conf) {
     _ctx.initForDefaultTypes();
   }
 
   @override
-  void reg(CustomTypeSpec spec, [String? tag]) {
-    if (tag == null){
+  void reg(CustomTypeSpec spec, [Object? tagOrTypeId]) {
+    if (tagOrTypeId == null) {
       String typeName = spec.dartType.toString();
       _regWithNamespace(spec, typeName, typeName);
       return;
     }
+    if (tagOrTypeId is int) {
+      _regWithTypeId(spec, tagOrTypeId);
+      return;
+    }
+    if (tagOrTypeId is! String) {
+      throw RegistrationArgumentException(tagOrTypeId);
+    }
+    String tag = tagOrTypeId;
     int idx = tag.lastIndexOf('.');
     if (idx == -1) {
       _regWithNamespace(spec, tag, tag);
-    }else{
+    } else {
       String ns = tag.substring(0, idx);
       String tn = tag.substring(idx + 1);
       _regWithNamespace(spec, tag, tn, ns);
@@ -81,14 +150,15 @@ final class XtypeResolverImpl extends XtypeResolver {
   @override
   void registerSerializer(Type type, Serializer ser) {
     TypeInfo? typeInfo = _ctx.type2TypeInfo[type];
-    if (typeInfo == null){
+    if (typeInfo == null) {
       throw UnregisteredTypeException(type);
     }
     typeInfo.ser = ser;
   }
 
-  void _regWithNamespace(CustomTypeSpec spec, String tag, String tn, [String 
ns= '']) {
-    assert(spec.objType == ObjType.NAMED_STRUCT || spec.objType == 
ObjType.NAMED_ENUM);
+  void _regWithNamespace(CustomTypeSpec spec, String tag, String tn,
+      [String ns = '']) {
+    ObjType resolvedObjType = _resolveObjTypeForTagRegistration(spec.objType);
     MetaStringBytes tnMsb = _msResolver.getOrCreateMetaStringBytes(
       _tstrEncoder.encodeTypeName(tn),
     );
@@ -97,30 +167,97 @@ final class XtypeResolverImpl extends XtypeResolver {
     );
     TypeInfo typeInfo = TypeInfo(
       spec.dartType,
-      spec.objType,
+      resolvedObjType,
       tag,
       tnMsb,
       nsMsb,
     );
     typeInfo.ser = _getSerFor(spec);
     _ctx.reg(typeInfo);
+    _type2Spec[typeInfo.dartType] = spec;
+  }
+
+  void _regWithTypeId(CustomTypeSpec spec, int userTypeId) {
+    final int normalizedTypeId = userTypeId & 0xFFFFFFFF;
+    ObjType resolvedObjType =
+        _resolveObjTypeForTypeIdRegistration(spec.objType);
+    TypeInfo typeInfo = TypeInfo(
+      spec.dartType,
+      resolvedObjType,
+      null,
+      null,
+      null,
+      userTypeId: normalizedTypeId,
+    );
+    typeInfo.ser = _getSerFor(spec);
+    _ctx.reg(typeInfo);
+    _type2Spec[typeInfo.dartType] = spec;
+    if (resolvedObjType == ObjType.STRUCT) {
+      _ctx.userTypeId2TypeInfo[
+              LongLongKey(ObjType.COMPATIBLE_STRUCT.id, normalizedTypeId)] =
+          typeInfo;
+    } else if (resolvedObjType == ObjType.COMPATIBLE_STRUCT) {
+      _ctx.userTypeId2TypeInfo[
+          LongLongKey(ObjType.STRUCT.id, normalizedTypeId)] = typeInfo;
+    }
+  }
+
+  ObjType _resolveObjTypeForTagRegistration(ObjType specObjType) {
+    switch (specObjType) {
+      case ObjType.NAMED_ENUM:
+      case ObjType.ENUM:
+        return ObjType.NAMED_ENUM;
+      case ObjType.NAMED_STRUCT:
+      case ObjType.STRUCT:
+      case ObjType.NAMED_COMPATIBLE_STRUCT:
+      case ObjType.COMPATIBLE_STRUCT:
+        return _ctx.conf.compatible
+            ? ObjType.NAMED_COMPATIBLE_STRUCT
+            : ObjType.NAMED_STRUCT;
+      case ObjType.NAMED_EXT:
+      case ObjType.EXT:
+        return ObjType.NAMED_EXT;
+      default:
+        throw RegistrationArgumentException(specObjType);
+    }
   }
 
+  ObjType _resolveObjTypeForTypeIdRegistration(ObjType specObjType) {
+    switch (specObjType) {
+      case ObjType.NAMED_ENUM:
+      case ObjType.ENUM:
+        return ObjType.ENUM;
+      case ObjType.NAMED_STRUCT:
+      case ObjType.STRUCT:
+      case ObjType.NAMED_COMPATIBLE_STRUCT:
+      case ObjType.COMPATIBLE_STRUCT:
+        return _ctx.conf.compatible
+            ? ObjType.COMPATIBLE_STRUCT
+            : ObjType.STRUCT;
+      case ObjType.NAMED_EXT:
+      case ObjType.EXT:
+        return ObjType.EXT;
+      default:
+        throw RegistrationArgumentException(specObjType);
+    }
+  }
 
   /// The ClassSer generated here will not analyze the corresponding ser for 
each TypeArg.
-  /// There are two considerations for this: 
-  /// First, it intends to delay the specific analysis until the first parsing 
of this Class, 
+  /// There are two considerations for this:
+  /// First, it intends to delay the specific analysis until the first parsing 
of this Class,
   /// to prevent too many tasks from being executed at the beginning.
-  /// Second, if the Ser corresponding to the arg is parsed here, 
-  /// many Enums may still be registered later, and they cannot be recognized 
here, 
+  /// Second, if the Ser corresponding to the arg is parsed here,
+  /// many Enums may still be registered later, and they cannot be recognized 
here,
   /// resulting in an error that they are not registered even though they are.
   Serializer _getSerFor(CustomTypeSpec spec) {
-    if (spec.objType == ObjType.NAMED_ENUM){
-      Serializer ser = EnumSerializer.cache.getSerializerWithSpec(_ctx.conf, 
spec, spec.dartType);
+    if (spec.objType == ObjType.NAMED_ENUM || spec.objType == ObjType.ENUM) {
+      Serializer ser = EnumSerializer.cache
+          .getSerializerWithSpec(_ctx.conf, spec, spec.dartType);
       return ser;
     }
     // Indicates ClassSer
-    return ClassSerializer.cache.getSerializerWithSpec(_ctx.conf, spec as 
ClassSpec, spec.dartType);
+    return ClassSerializer.cache
+        .getSerializerWithSpec(_ctx.conf, spec as ClassSpec, spec.dartType);
   }
 
   /// This type must be a user-defined class or enum
@@ -128,7 +265,7 @@ final class XtypeResolverImpl extends XtypeResolver {
   @inline
   String getTagByCustomDartType(Type type) {
     String? tag = _ctx.type2TypeInfo[type]?.tag;
-    if (tag == null){
+    if (tag == null) {
       throw UnregisteredTypeException(type);
     }
     return tag;
@@ -137,13 +274,15 @@ final class XtypeResolverImpl extends XtypeResolver {
   @override
   void setSersForTypeWrap(List<TypeSpecWrap> typeWraps) {
     TypeSpecWrap wrap;
-    for (int i = 0; i < typeWraps.length; ++i){
+    for (int i = 0; i < typeWraps.length; ++i) {
       wrap = typeWraps[i];
-      if (wrap.certainForSer){
+      if (wrap.certainForSer) {
         wrap.ser = _ctx.type2TypeInfo[wrap.type]!.ser;
-      }else if (wrap.objType == ObjType.LIST){
+      } else if (wrap.objType == ObjType.LIST) {
         wrap.ser = _ctx.abstractListSer;
-      }else if (wrap.objType == ObjType.MAP) {
+      } else if (wrap.objType == ObjType.SET) {
+        wrap.ser = _ctx.abstractSetSer;
+      } else if (wrap.objType == ObjType.MAP) {
         wrap.ser = _ctx.abstractMapSer;
       }
       // At this point, ser is not set, ser is still null
@@ -151,29 +290,55 @@ final class XtypeResolverImpl extends XtypeResolver {
     }
   }
 
+  @override
+  void resetWriteContext() {
+    _writeTypeToIndex.clear();
+  }
+
+  @override
+  void resetReadContext() {
+    _readTypeInfos.clear();
+  }
+
   @override
   TypeInfo readTypeInfo(ByteReader br) {
     int xtypeId = br.readUint8();
     ObjType xtype = ObjType.fromId(xtypeId)!;
-    switch(xtype){
+    switch (xtype) {
       case ObjType.ENUM:
       case ObjType.STRUCT:
-      case ObjType.COMPATIBLE_STRUCT:
       case ObjType.EXT:
         int userTypeId = br.readVarUint32();
-        TypeInfo? idTypeInfo = _ctx.userTypeId2TypeInfo[LongLongKey(xtypeId, 
userTypeId)];
+        TypeInfo? idTypeInfo =
+            _ctx.userTypeId2TypeInfo[LongLongKey(xtypeId, userTypeId)];
+        if (idTypeInfo == null && xtype == ObjType.STRUCT) {
+          idTypeInfo = _ctx.userTypeId2TypeInfo[
+              LongLongKey(ObjType.COMPATIBLE_STRUCT.id, userTypeId)];
+        } else if (idTypeInfo == null && xtype == ObjType.COMPATIBLE_STRUCT) {
+          idTypeInfo = _ctx
+              .userTypeId2TypeInfo[LongLongKey(ObjType.STRUCT.id, userTypeId)];
+        }
         if (idTypeInfo != null) {
           return idTypeInfo;
         }
-        throw UnregisteredTypeException(xtype);
+        throw UnregisteredTypeException(
+            '${xtype.name}(userTypeId=$userTypeId)');
+      case ObjType.COMPATIBLE_STRUCT:
+      case ObjType.NAMED_COMPATIBLE_STRUCT:
+        return _readSharedTypeMeta(br);
       case ObjType.NAMED_ENUM:
       case ObjType.NAMED_STRUCT:
-      case ObjType.NAMED_COMPATIBLE_STRUCT:
       case ObjType.NAMED_EXT:
+      case ObjType.NAMED_UNION:
+        if (_ctx.conf.compatible) {
+          return _readSharedTypeMeta(br);
+        }
         MetaStringBytes pkgBytes = _msResolver.readMetaStringBytes(br);
         // assert(pkgBytes.length == 0); // fory dart does not support package
-        MetaStringBytes simpleClassNameBytes = 
_msResolver.readMetaStringBytes(br);
-        LongLongKey key = LongLongKey(pkgBytes.hashCode, 
simpleClassNameBytes.hashCode);
+        MetaStringBytes simpleClassNameBytes =
+            _msResolver.readMetaStringBytes(br);
+        LongLongKey key =
+            LongLongKey(pkgBytes.hashCode, simpleClassNameBytes.hashCode);
         TypeInfo? typeInfo = _tagHash2Info[key];
         if (typeInfo != null) {
           // Indicates that it has been registered
@@ -211,38 +376,406 @@ final class XtypeResolverImpl extends XtypeResolver {
   }
 
   @override
-  TypeInfo writeGetTypeInfo(ByteWriter bw, Object obj, SerializerPack pack){
+  TypeInfo writeGetTypeInfo(ByteWriter bw, Object obj, SerializerPack pack) {
     Type dartType = dartTypeResolver.getForyType(obj);
     TypeInfo? typeInfo = _ctx.type2TypeInfo[dartType];
-    if (typeInfo == null){
+    if (typeInfo == null) {
       throw UnregisteredTypeException(dartType);
     }
     bw.writeUint8(typeInfo.objType.id);
-    switch(typeInfo.objType){
+    switch (typeInfo.objType) {
       case ObjType.ENUM:
       case ObjType.STRUCT:
-      case ObjType.COMPATIBLE_STRUCT:
       case ObjType.EXT:
+      case ObjType.TYPED_UNION:
         bw.writeVarUint32(typeInfo.userTypeId);
         break;
+      case ObjType.COMPATIBLE_STRUCT:
+      case ObjType.NAMED_COMPATIBLE_STRUCT:
+        _writeSharedTypeMeta(bw, typeInfo);
+        break;
       case ObjType.NAMED_ENUM:
       case ObjType.NAMED_STRUCT:
-      case ObjType.NAMED_COMPATIBLE_STRUCT:
       case ObjType.NAMED_EXT:
-        pack.msWritingResolver.writeMetaStringBytes(bw, typeInfo.nsBytes!);
-        pack.msWritingResolver.writeMetaStringBytes(bw, 
typeInfo.typeNameBytes!);
+      case ObjType.NAMED_UNION:
+        if (_ctx.conf.compatible) {
+          _writeSharedTypeMeta(bw, typeInfo);
+        } else {
+          pack.msWritingResolver.writeMetaStringBytes(bw, typeInfo.nsBytes!);
+          pack.msWritingResolver
+              .writeMetaStringBytes(bw, typeInfo.typeNameBytes!);
+        }
         break;
       default:
         break;
     }
     return typeInfo;
   }
-  
+
+  TypeInfo _readSharedTypeMeta(ByteReader br) {
+    final int marker = br.readVarUint32();
+    final bool isRef = (marker & 1) == 1;
+    final int index = marker >>> 1;
+    if (isRef) {
+      if (index < 0 || index >= _readTypeInfos.length) {
+        throw UnregisteredTypeException(
+            'Shared type index out of bounds: $index');
+      }
+      return _readTypeInfos[index];
+    }
+    final int id = br.readInt64();
+    final int unsignedId = id & _allBits64Mask;
+    int size = unsignedId & _metaSizeMask;
+    if (size == _metaSizeMask) {
+      size += br.readVarUint32();
+    }
+    final Uint8List bodyBytes = br.copyBytes(size);
+    if ((unsignedId & _compressMetaFlag) != 0) {
+      throw UnregisteredTypeException('Compressed TypeDef is not supported');
+    }
+    final TypeInfo typeInfo = _readTypeInfoFromTypeDefBody(bodyBytes);
+    _readTypeInfos.add(typeInfo);
+    return typeInfo;
+  }
+
+  TypeInfo _readTypeInfoFromTypeDefBody(Uint8List bodyBytes) {
+    final ByteReader bodyReader = ByteReader.forBytes(bodyBytes);
+    int header = bodyReader.readUint8();
+    int numFields = header & _smallFieldThreshold;
+    if (numFields == _smallFieldThreshold) {
+      numFields += bodyReader.readVarUint32Small7();
+    }
+    if ((header & _registerByNameFlag) != 0) {
+      final String namespace = _readPackageName(bodyReader);
+      final String typeName = _readTypeName(bodyReader);
+      final String qualifiedName =
+          StringUtil.addingTypeNameAndNs(namespace, typeName);
+      final TypeInfo? typeInfo = _ctx.tag2TypeInfo[qualifiedName];
+      if (typeInfo == null) {
+        throw UnregisteredTagException(qualifiedName);
+      }
+      return typeInfo;
+    }
+    final int typeId = bodyReader.readUint8();
+    final int userTypeId = bodyReader.readVarUint32();
+    final TypeInfo? typeInfo = _lookupTypeInfoByUserTypeId(typeId, userTypeId);
+    if (typeInfo == null) {
+      throw UnregisteredTypeException('typeId=$typeId,userTypeId=$userTypeId');
+    }
+    return typeInfo;
+  }
+
+  TypeInfo? _lookupTypeInfoByUserTypeId(int typeId, int userTypeId) {
+    TypeInfo? typeInfo =
+        _ctx.userTypeId2TypeInfo[LongLongKey(typeId, userTypeId)];
+    if (typeInfo == null && typeId == ObjType.STRUCT.id) {
+      typeInfo = _ctx.userTypeId2TypeInfo[
+          LongLongKey(ObjType.COMPATIBLE_STRUCT.id, userTypeId)];
+    } else if (typeInfo == null && typeId == ObjType.COMPATIBLE_STRUCT.id) {
+      typeInfo =
+          _ctx.userTypeId2TypeInfo[LongLongKey(ObjType.STRUCT.id, userTypeId)];
+    }
+    return typeInfo;
+  }
+
+  String _readPackageName(ByteReader br) {
+    return _readTypeNameInternal(
+        br, _packageNameDecoder, _packageNameEncodingByFlag);
+  }
+
+  String _readTypeName(ByteReader br) {
+    return _readTypeNameInternal(br, _typeNameDecoder, 
_typeNameEncodingByFlag);
+  }
+
+  String _readTypeNameInternal(
+    ByteReader br,
+    MetaStringDecoder decoder,
+    MetaStringEncoding Function(int) getEncodingByFlag,
+  ) {
+    final int header = br.readUint8();
+    final int encodingFlag = header & 3;
+    final MetaStringEncoding encoding = getEncodingByFlag(encodingFlag);
+    int size = header >>> 2;
+    if (size == _bigNameThreshold) {
+      size += br.readVarUint32Small7();
+    }
+    final Uint8List bytes = br.readBytesView(size);
+    return decoder.decode(bytes, encoding);
+  }
+
+  void _writeSharedTypeMeta(ByteWriter bw, TypeInfo typeInfo) {
+    final int? existingIndex = _writeTypeToIndex[typeInfo.dartType];
+    if (existingIndex != null) {
+      bw.writeVarUint32((existingIndex << 1) | 1);
+      return;
+    }
+    final int index = _writeTypeToIndex.length;
+    _writeTypeToIndex[typeInfo.dartType] = index;
+    bw.writeVarUint32(index << 1);
+    final Uint8List typeDef = _typeToEncodedTypeDef.putIfAbsent(
+      typeInfo.dartType,
+      () => _encodeTypeDefFor(typeInfo),
+    );
+    bw.writeBytes(typeDef);
+  }
+
+  Uint8List _encodeTypeDefFor(TypeInfo typeInfo) {
+    final CustomTypeSpec? spec = _type2Spec[typeInfo.dartType];
+    if (spec == null) {
+      throw UnregisteredTypeException(typeInfo.dartType);
+    }
+    final List<FieldSpec> fields = _fieldsForTypeDef(spec);
+    final Uint8List body = _buildTypeDefBody(typeInfo, fields);
+    final int bodySize = body.length;
+    final int hash50 =
+        Murmur3Hash.hash128x64(body, bodySize, 0, _seed47).$1 & 
_hashMask50Bits;
+    int id = _toSignedInt64(hash50 << 14);
+    id &= ~(_metaSizeMask | _hasFieldsMetaFlag | _compressMetaFlag);
+    if (fields.isNotEmpty) {
+      id |= _hasFieldsMetaFlag;
+    }
+    if (bodySize >= _metaSizeMask) {
+      id |= _metaSizeMask;
+    } else {
+      id |= bodySize;
+    }
+    id = _toSignedInt64(id);
+
+    final ByteWriter writer = ByteWriter();
+    writer.writeInt64(id);
+    if (bodySize >= _metaSizeMask) {
+      writer.writeVarUint32(bodySize - _metaSizeMask);
+    }
+    writer.writeBytes(body);
+    return writer.takeBytes();
+  }
+
+  List<FieldSpec> _fieldsForTypeDef(CustomTypeSpec spec) {
+    if (spec is! ClassSpec) {
+      return const <FieldSpec>[];
+    }
+    final List<FieldSpec> fields = <FieldSpec>[];
+    for (int i = 0; i < spec.fields.length; ++i) {
+      final FieldSpec field = spec.fields[i];
+      if (field.includeToFory) {
+        fields.add(field);
+      }
+    }
+    return fields;
+  }
+
+  Uint8List _buildTypeDefBody(TypeInfo typeInfo, List<FieldSpec> fields) {
+    final ByteWriter writer = ByteWriter();
+    int header = fields.length >= _smallFieldThreshold
+        ? _smallFieldThreshold
+        : fields.length;
+    final bool registerByName = typeInfo.tag != null;
+    if (registerByName) {
+      header |= _registerByNameFlag;
+    }
+    writer.writeUint8(header);
+    if (fields.length >= _smallFieldThreshold) {
+      writer.writeVarUint32Small7(fields.length - _smallFieldThreshold);
+    }
+    if (registerByName) {
+      final String ns = _msResolver.decodeNamespace(typeInfo.nsBytes!);
+      final String typeName =
+          _msResolver.decodeTypename(typeInfo.typeNameBytes!);
+      _writePackageName(writer, ns);
+      _writeTypeName(writer, typeName);
+    } else {
+      writer.writeUint8(typeInfo.objType.id);
+      writer.writeVarUint32(typeInfo.userTypeId);
+    }
+    for (int i = 0; i < fields.length; ++i) {
+      _writeTypeDefField(writer, fields[i]);
+    }
+    return writer.takeBytes();
+  }
+
+  void _writePackageName(ByteWriter writer, String value) {
+    final meta = _packageNameEncoder.encodeByAllowedEncodings(
+        value, _packageNameAllowedEncodings);
+    _writeName(writer, meta.bytes, _packageNameEncodingFlag(meta.encoding));
+  }
+
+  void _writeTypeName(ByteWriter writer, String value) {
+    final meta = _typeNameEncoder.encodeByAllowedEncodings(
+        value, _typeNameAllowedEncodings);
+    _writeName(writer, meta.bytes, _typeNameEncodingFlag(meta.encoding));
+  }
+
+  void _writeName(ByteWriter writer, Uint8List encodedBytes, int encodingFlag) 
{
+    final int size = encodedBytes.length;
+    if (size >= _bigNameThreshold) {
+      writer.writeUint8((_bigNameThreshold << 2) | encodingFlag);
+      writer.writeVarUint32Small7(size - _bigNameThreshold);
+    } else {
+      writer.writeUint8((size << 2) | encodingFlag);
+    }
+    writer.writeBytes(encodedBytes);
+  }
+
+  void _writeTypeDefField(ByteWriter writer, FieldSpec field) {
+    final String fieldName = 
StringUtil.lowerCamelToLowerUnderscore(field.name);
+    final meta = _fieldNameEncoder.encodeByAllowedEncodings(
+        fieldName, _fieldNameAllowedEncodings);
+    final Uint8List encodedName = meta.bytes;
+    final int encodingFlag = _fieldNameEncodingFlag(meta.encoding);
+    int size = encodedName.length - 1;
+    int header = encodingFlag << 6;
+    if (field.typeSpec.nullable) {
+      header |= 2;
+    }
+    if (size >= _fieldNameSizeThreshold) {
+      header |= (_fieldNameSizeThreshold << 2);
+      writer.writeUint8(header);
+      writer.writeVarUint32Small7(size - _fieldNameSizeThreshold);
+    } else {
+      header |= (size << 2);
+      writer.writeUint8(header);
+    }
+    final int typeId = _fieldTypeId(field.typeSpec);
+    writer.writeUint8(typeId);
+    _writeNestedTypeInfo(writer, field.typeSpec);
+    writer.writeBytes(encodedName);
+  }
+
+  void _writeNestedTypeInfo(ByteWriter writer, TypeSpec typeSpec) {
+    final int typeId = _fieldTypeId(typeSpec);
+    switch (ObjType.fromId(typeId)) {
+      case ObjType.LIST:
+      case ObjType.SET:
+        final TypeSpec elem = typeSpec.genericsArgs.isNotEmpty
+            ? typeSpec.genericsArgs[0]
+            : const TypeSpec(
+                Object, ObjType.UNKNOWN, true, false, null, <TypeSpec>[]);
+        _writeNestedFieldTypeHeader(writer, elem);
+        _writeNestedTypeInfo(writer, elem);
+        break;
+      case ObjType.MAP:
+        final TypeSpec key = typeSpec.genericsArgs.isNotEmpty
+            ? typeSpec.genericsArgs[0]
+            : const TypeSpec(
+                Object, ObjType.UNKNOWN, true, false, null, <TypeSpec>[]);
+        final TypeSpec value = typeSpec.genericsArgs.length > 1
+            ? typeSpec.genericsArgs[1]
+            : const TypeSpec(
+                Object, ObjType.UNKNOWN, true, false, null, <TypeSpec>[]);
+        _writeNestedFieldTypeHeader(writer, key);
+        _writeNestedTypeInfo(writer, key);
+        _writeNestedFieldTypeHeader(writer, value);
+        _writeNestedTypeInfo(writer, value);
+        break;
+      default:
+        break;
+    }
+  }
+
+  void _writeNestedFieldTypeHeader(ByteWriter writer, TypeSpec typeSpec) {
+    int header = _fieldTypeId(typeSpec) << 2;
+    if (typeSpec.nullable) {
+      header |= 2;
+    }
+    writer.writeVarUint32Small7(header);
+  }
+
+  int _fieldTypeId(TypeSpec typeSpec) {
+    switch (typeSpec.objType) {
+      case ObjType.NAMED_ENUM:
+        return ObjType.ENUM.id;
+      case ObjType.NAMED_STRUCT:
+        return ObjType.STRUCT.id;
+      case ObjType.NAMED_COMPATIBLE_STRUCT:
+        return ObjType.COMPATIBLE_STRUCT.id;
+      case ObjType.NAMED_EXT:
+        return ObjType.EXT.id;
+      case ObjType.TYPED_UNION:
+      case ObjType.NAMED_UNION:
+        return ObjType.UNION.id;
+      default:
+        return typeSpec.objType.id;
+    }
+  }
+
+  int _packageNameEncodingFlag(MetaStringEncoding encoding) {
+    switch (encoding) {
+      case MetaStringEncoding.utf8:
+        return 0;
+      case MetaStringEncoding.atls:
+        return 1;
+      case MetaStringEncoding.luds:
+        return 2;
+      default:
+        throw RegistrationArgumentException(encoding);
+    }
+  }
+
+  int _typeNameEncodingFlag(MetaStringEncoding encoding) {
+    switch (encoding) {
+      case MetaStringEncoding.utf8:
+        return 0;
+      case MetaStringEncoding.atls:
+        return 1;
+      case MetaStringEncoding.luds:
+        return 2;
+      case MetaStringEncoding.ftls:
+        return 3;
+      default:
+        throw RegistrationArgumentException(encoding);
+    }
+  }
+
+  int _fieldNameEncodingFlag(MetaStringEncoding encoding) {
+    switch (encoding) {
+      case MetaStringEncoding.utf8:
+        return 0;
+      case MetaStringEncoding.atls:
+        return 1;
+      case MetaStringEncoding.luds:
+        return 2;
+      default:
+        throw RegistrationArgumentException(encoding);
+    }
+  }
+
+  MetaStringEncoding _packageNameEncodingByFlag(int flag) {
+    switch (flag) {
+      case 0:
+        return MetaStringEncoding.utf8;
+      case 1:
+        return MetaStringEncoding.atls;
+      case 2:
+        return MetaStringEncoding.luds;
+      default:
+        throw RegistrationArgumentException(flag);
+    }
+  }
+
+  MetaStringEncoding _typeNameEncodingByFlag(int flag) {
+    switch (flag) {
+      case 0:
+        return MetaStringEncoding.utf8;
+      case 1:
+        return MetaStringEncoding.atls;
+      case 2:
+        return MetaStringEncoding.luds;
+      case 3:
+        return MetaStringEncoding.ftls;
+      default:
+        throw RegistrationArgumentException(flag);
+    }
+  }
+
+  int _toSignedInt64(int value) {
+    return value.toSigned(64);
+  }
+
   // for test only
   @override
   StructHashPair getHashPairForTest(Type type) {
     TypeInfo? typeInfo = _ctx.type2TypeInfo[type];
-    if (typeInfo == null){
+    if (typeInfo == null) {
       throw UnregisteredTypeException(type);
     }
     ClassSerializer ser = typeInfo.ser as ClassSerializer;
diff --git a/dart/packages/fory/lib/src/resolver/struct_hash_resolver.dart 
b/dart/packages/fory/lib/src/resolver/struct_hash_resolver.dart
index 6fda45b51..eaf5661cf 100644
--- a/dart/packages/fory/lib/src/resolver/struct_hash_resolver.dart
+++ b/dart/packages/fory/lib/src/resolver/struct_hash_resolver.dart
@@ -17,82 +17,96 @@
  * under the License.
  */
 
-import 'dart:collection';
+import 'dart:convert';
+import 'dart:typed_data';
 import 'package:fory/src/codegen/entity/struct_hash_pair.dart';
 import 'package:fory/src/const/types.dart';
 import 'package:fory/src/meta/specs/field_spec.dart';
+import 'package:fory/src/util/murmur3hash.dart';
 import 'package:fory/src/util/string_util.dart';
 
-class StructHashResolver{
+class StructHashResolver {
   // singleton
   static final StructHashResolver _instance = StructHashResolver._internal();
   static StructHashResolver get inst => _instance;
   StructHashResolver._internal();
 
-  // key: utf8 string objectIdentityHash, value: hash value
-  final Map<int, int> _stringObjToHash = HashMap();
-
-  StructHashPair computeHash(List<FieldSpec> fields, String Function(Type 
type) getTagByType) {
-    if (fields.isEmpty) {
-      return const StructHashPair(17, 17);
+  StructHashPair computeHash(
+      List<FieldSpec> fields, String Function(Type type) _) {
+    final List<FieldSpec> fromFields = <FieldSpec>[];
+    final List<FieldSpec> toFields = <FieldSpec>[];
+    for (int i = 0; i < fields.length; ++i) {
+      final FieldSpec field = fields[i];
+      if (field.includeFromFory) {
+        fromFields.add(field);
+      }
+      if (field.includeToFory) {
+        toFields.add(field);
+      }
     }
-    int hashF = 17;
-    int hashT = 17;
-    // Here, checking whether align means to see if includeFromFory and 
includeToFory are the same,
-    // and both cannot be false at the same time, otherwise static analysis 
will not retain this field,
-    // so actually both are true.
-    bool stillAlign = fields[0].includeFromFory == fields[0].includeToFory;
-
-    for (int i = 0; i < fields.length; ++i){
-      if (stillAlign){
-        // Here, stillAlign means fields[i] is aligned
-        if (i < fields.length - 1){
-          stillAlign = fields[i+1].includeFromFory == 
fields[i+1].includeToFory;
+    if (fromFields.length == toFields.length) {
+      bool same = true;
+      for (int i = 0; i < fromFields.length; ++i) {
+        if (!identical(fromFields[i], toFields[i])) {
+          same = false;
+          break;
         }
-        hashF = _computeFieldHash(hashF, fields[i], getTagByType);
-        hashT = hashF;
-        continue;
       }
-      // Here, stillAlign means fields[i] is unaligned
-      if (fields[i].includeFromFory) hashF = _computeFieldHash(hashF, 
fields[i], getTagByType);
-      if (fields[i].includeToFory) hashT = _computeFieldHash(hashT, fields[i], 
getTagByType);
+      if (same) {
+        final int hash = _computeFingerprintHash(fromFields);
+        return StructHashPair(hash, hash);
+      }
     }
-    return StructHashPair(hashF, hashT);
+    return StructHashPair(
+      _computeFingerprintHash(fromFields),
+      _computeFingerprintHash(toFields),
+    );
   }
 
-  int _computeFieldHash(int hash, FieldSpec field, String Function(Type type) 
getTagByType) {
-    late int id;
-    String tag;
-    ObjType objType = field.typeSpec.objType;
-    switch(objType){
-      case ObjType.LIST:
-        id = ObjType.LIST.id;
-        break;
-      case ObjType.MAP:
-        id = ObjType.MAP.id;
-        break;
-      case ObjType.UNKNOWN:
-        id = 0;
-        break;
-      default:
-        if (objType.isStructType()){
-          tag = getTagByType(field.typeSpec.type);
-          int tagObjHashCode = identityHashCode(tag);
-          int? hashVal = _stringObjToHash[tagObjHashCode];
-          if (hashVal != null) {
-            id = hashVal;
-          }else{
-            id = StringUtil.computeUtf8StringHash(tag);
-            _stringObjToHash[tagObjHashCode] = id;
-          }
-        }else {
-          id = objType.id.abs();
-        }
+  int _computeFingerprintHash(List<FieldSpec> fields) {
+    final List<String> entries =
+        List<String>.filled(fields.length, '', growable: false);
+    for (int i = 0; i < fields.length; ++i) {
+      final FieldSpec field = fields[i];
+      final String fieldName =
+          StringUtil.lowerCamelToLowerUnderscore(field.name);
+      final int typeId = _fingerprintTypeId(field.typeSpec.objType);
+      final int nullable = field.typeSpec.nullable ? 1 : 0;
+      entries[i] = '$fieldName,$typeId,0,$nullable;';
+    }
+    entries.sort();
+    final StringBuffer fingerprint = StringBuffer();
+    for (int i = 0; i < entries.length; ++i) {
+      fingerprint.write(entries[i]);
+    }
+    final Uint8List bytes =
+        Uint8List.fromList(utf8.encode(fingerprint.toString()));
+    final int hash64 = Murmur3Hash.hash128x64(bytes, bytes.length, 0, 47).$1;
+    return (hash64 & 0xffffffff).toSigned(32);
+  }
+
+  int _fingerprintTypeId(ObjType objType) {
+    if (objType == ObjType.UNKNOWN) {
+      return ObjType.UNKNOWN.id;
+    }
+    if (objType == ObjType.LIST ||
+        objType == ObjType.SET ||
+        objType == ObjType.MAP) {
+      return objType.id;
     }
-    int fieldHash = hash * 31 + id;
-    while (fieldHash > 0x7FFFFFFF){
-      fieldHash ~/= 7;
+    if (objType == ObjType.ENUM ||
+        objType == ObjType.NAMED_ENUM ||
+        objType == ObjType.STRUCT ||
+        objType == ObjType.COMPATIBLE_STRUCT ||
+        objType == ObjType.NAMED_STRUCT ||
+        objType == ObjType.NAMED_COMPATIBLE_STRUCT ||
+        objType == ObjType.EXT ||
+        objType == ObjType.NAMED_EXT ||
+        objType == ObjType.UNION ||
+        objType == ObjType.TYPED_UNION ||
+        objType == ObjType.NAMED_UNION) {
+      return ObjType.UNKNOWN.id;
     }
-    return fieldHash;
+    return objType.id;
   }
 }
diff --git a/dart/packages/fory/lib/src/resolver/xtype_resolver.dart 
b/dart/packages/fory/lib/src/resolver/xtype_resolver.dart
index 90924e3ce..baf9fdfd7 100644
--- a/dart/packages/fory/lib/src/resolver/xtype_resolver.dart
+++ b/dart/packages/fory/lib/src/resolver/xtype_resolver.dart
@@ -28,20 +28,23 @@ import 'package:fory/src/memory/byte_writer.dart';
 import 'package:fory/src/meta/specs/custom_type_spec.dart';
 import 'package:fory/src/serializer_pack.dart';
 
-abstract base class XtypeResolver{
-
+abstract base class XtypeResolver {
   const XtypeResolver(ForyConfig conf);
 
   static XtypeResolver newOne(ForyConfig conf) {
     return XtypeResolverImpl(conf);
   }
 
-  void reg(CustomTypeSpec spec, [String? tag]);
+  void reg(CustomTypeSpec spec, [Object? tagOrTypeId]);
 
   void registerSerializer(Type type, Serializer ser);
 
   void setSersForTypeWrap(List<TypeSpecWrap> typeWraps);
 
+  void resetWriteContext();
+
+  void resetReadContext();
+
   TypeInfo readTypeInfo(ByteReader br);
 
   String getTagByCustomDartType(Type type);
@@ -52,4 +55,4 @@ abstract base class XtypeResolver{
   StructHashPair getHashPairForTest(
     Type type,
   );
-}
\ No newline at end of file
+}
diff --git a/dart/packages/fory/lib/src/serialize_coordinator.dart 
b/dart/packages/fory/lib/src/serialize_coordinator.dart
index 655cf8731..db07b8e2f 100644
--- a/dart/packages/fory/lib/src/serialize_coordinator.dart
+++ b/dart/packages/fory/lib/src/serialize_coordinator.dart
@@ -38,14 +38,17 @@ import 'package:fory/src/datatype/int32.dart';
 import 'package:fory/src/datatype/float32.dart';
 
 class SerializeCoordinator {
-  static final SerializeCoordinator _instance = 
SerializeCoordinator._internal();
+  static final SerializeCoordinator _instance =
+      SerializeCoordinator._internal();
   static SerializeCoordinator get I => _instance;
   SerializeCoordinator._internal();
 
   static final ForyHeaderSerializer _foryHeaderSer = ForyHeaderSerializer.I;
 
-  void _write(Object? obj, ForyConfig conf, XtypeResolver xtypeResolver, 
ByteWriter writer) {
+  void _write(Object? obj, ForyConfig conf, XtypeResolver xtypeResolver,
+      ByteWriter writer) {
     _foryHeaderSer.write(writer, obj == null, conf);
+    xtypeResolver.resetWriteContext();
     SerializerPack pack = SerializerPack(
       StructHashResolver.inst,
       xtypeResolver.getTagByCustomDartType,
@@ -60,13 +63,18 @@ class SerializeCoordinator {
     // pack.resetAndRecycle();
   }
 
-  Uint8List write(Object? obj, ForyConfig conf, XtypeResolver xtypeResolver,) {
+  Uint8List write(
+    Object? obj,
+    ForyConfig conf,
+    XtypeResolver xtypeResolver,
+  ) {
     ByteWriter bw = ByteWriter();
     _write(obj, conf, xtypeResolver, bw);
     return bw.takeBytes();
   }
 
-  void writeWithWriter(Object? obj, ForyConfig conf, XtypeResolver 
xtypeResolver, ByteWriter writer) {
+  void writeWithWriter(Object? obj, ForyConfig conf,
+      XtypeResolver xtypeResolver, ByteWriter writer) {
     _write(obj, conf, xtypeResolver, writer);
   }
 
@@ -107,7 +115,39 @@ class SerializeCoordinator {
     }
   }
 
-  void xWriteRefWithSer(ByteWriter bw, Serializer ser, Object? obj, 
SerializerPack pack) {
+  void xWriteNonRefNoSer(ByteWriter bw, Object obj, SerializerPack pack) {
+    TypeInfo typeInfo = pack.xtypeResolver.writeGetTypeInfo(bw, obj, pack);
+    switch (typeInfo.objType) {
+      case ObjType.BOOL:
+        bw.writeBool(obj as bool);
+        break;
+      case ObjType.INT8:
+        bw.writeInt8((obj as Int8).value);
+        break;
+      case ObjType.INT16:
+        bw.writeInt16((obj as Int16).value);
+        break;
+      case ObjType.INT32:
+      case ObjType.VAR_INT32:
+        bw.writeVarInt32((obj as Int32).value);
+        break;
+      case ObjType.INT64:
+      case ObjType.VAR_INT64:
+        bw.writeVarInt64(obj as int);
+        break;
+      case ObjType.FLOAT32:
+        bw.writeFloat32((obj as Float32).value);
+        break;
+      case ObjType.FLOAT64:
+        bw.writeFloat64(obj as double);
+        break;
+      default:
+        typeInfo.ser.write(bw, obj, pack);
+    }
+  }
+
+  void xWriteRefWithSer(
+      ByteWriter bw, Serializer ser, Object? obj, SerializerPack pack) {
     if (ser.writeRef) {
       SerializationRefMeta serRef = pack.refResolver.getRefId(obj);
       bw.writeInt8(serRef.refFlag.id);
@@ -116,11 +156,11 @@ class SerializeCoordinator {
       }
       if (serRef.refFlag.noNeedToSer) return;
       ser.write(bw, obj, pack);
-    }else{
+    } else {
       RefFlag refFlag = pack.noRefResolver.getRefFlag(obj);
       bw.writeInt8(refFlag.id);
       if (refFlag.noNeedToSer) return;
       ser.write(bw, obj, pack);
     }
   }
-}
\ No newline at end of file
+}
diff --git a/dart/packages/fory/lib/src/serializer/class_serializer.dart 
b/dart/packages/fory/lib/src/serializer/class_serializer.dart
index 0e7808e2e..03df0f1da 100644
--- a/dart/packages/fory/lib/src/serializer/class_serializer.dart
+++ b/dart/packages/fory/lib/src/serializer/class_serializer.dart
@@ -33,31 +33,32 @@ import 'package:fory/src/serializer/serializer.dart';
 import 'package:fory/src/serializer/serializer_cache.dart';
 import 'package:fory/src/serializer_pack.dart';
 
-final class ClassSerializerCache extends SerializerCache{
+final class ClassSerializerCache extends SerializerCache {
   const ClassSerializerCache();
 
   @override
-  ClassSerializer getSerializerWithSpec(ForyConfig conf, covariant ClassSpec 
spec, Type dartType){
+  ClassSerializer getSerializerWithSpec(
+      ForyConfig conf, covariant ClassSpec spec, Type dartType) {
     List<TypeSpecWrap> typeWraps = TypeSpecWrap.ofList(spec.fields);
     return ClassSerializer(
       spec.fields,
       spec.construct,
       spec.noArgConstruct,
       typeWraps,
+      conf.compatible,
       conf.refTracking,
     );
   }
 }
 
-
-final class ClassSerializer extends CustomSerializer<Object>{
-
+final class ClassSerializer extends CustomSerializer<Object> {
   static const ClassSerializerCache cache = ClassSerializerCache();
 
   final List<FieldSpec> _fields;
   final HasArgsCons? _construct;
   final NoArgsCons? _noArgConstruct;
   final List<TypeSpecWrap> _fieldTypeWraps;
+  final bool _compatible;
 
   late final int _fromForyHash;
   late final int _toForyHash;
@@ -66,61 +67,71 @@ final class ClassSerializer extends 
CustomSerializer<Object>{
   bool _fieldsSersComputed = false;
 
   ClassSerializer(
-      this._fields,
-      this._construct,
-      this._noArgConstruct,
-      this._fieldTypeWraps,
-      bool refWrite,
-      ): super(ObjType.NAMED_STRUCT, refWrite,);
-
+    this._fields,
+    this._construct,
+    this._noArgConstruct,
+    this._fieldTypeWraps,
+    this._compatible,
+    bool refWrite,
+  ) : super(
+          ObjType.NAMED_STRUCT,
+          refWrite,
+        );
 
-  StructHashPair getHashPairForTest(StructHashResolver structHashResolver, 
String Function(Type type) getTagByDartType){
+  StructHashPair getHashPairForTest(StructHashResolver structHashResolver,
+      String Function(Type type) getTagByDartType) {
     return structHashResolver.computeHash(_fields, getTagByDartType);
   }
 
   @override
   Object read(ByteReader br, int refId, DeserializerPack pack) {
-    if (!_fieldsSersComputed){
+    if (!_fieldsSersComputed) {
       pack.xtypeResolver.setSersForTypeWrap(_fieldTypeWraps);
       _fieldsSersComputed = true;
     }
-    if (!_hashComputed){
-      var pair = pack.structHashResolver.computeHash(_fields, 
pack.getTagByDartType);
+    if (!_compatible && !_hashComputed) {
+      var pair =
+          pack.structHashResolver.computeHash(_fields, pack.getTagByDartType);
       _fromForyHash = pair.fromForyHash;
       _toForyHash = pair.toForyHash;
       _hashComputed = true;
     }
-    int readFHash = br.readInt32();
-    if (readFHash != _fromForyHash){
-      throw ForyMismatchException(
-        readFHash,
-        _fromForyHash,
-        'The field hash read from bytes does not match the expected hash.',
-      );
+    if (!_compatible) {
+      int readFHash = br.readInt32();
+      if (readFHash != _fromForyHash) {
+        throw ForyMismatchException(
+          readFHash,
+          _fromForyHash,
+          'The field hash read from bytes does not match the expected hash.',
+        );
+      }
     }
     if (_noArgConstruct == null) {
       return _byParameterizedCons(br, refId, pack);
     }
     Object obj = _noArgConstruct();
-    pack.refResolver.setRefTheLatestId(obj); // Need to ref immediately to 
prevent subsequent circular references and for normal reference tracking
+    pack.refResolver.setRefTheLatestId(
+        obj); // Need to ref immediately to prevent subsequent circular 
references and for normal reference tracking
     for (int i = 0; i < _fields.length; ++i) {
       FieldSpec fieldSpec = _fields[i];
       if (!fieldSpec.includeFromFory) continue;
       TypeSpecWrap typeWrap = _fieldTypeWraps[i];
       bool hasGenericsParam = typeWrap.hasGenericsParam;
-      if (hasGenericsParam){
+      if (hasGenericsParam) {
         pack.typeWrapStack.push(typeWrap);
       }
       late Object? fieldValue;
       Serializer? ser = _fieldTypeWraps[i].ser;
       if (ser == null) {
         fieldValue = pack.foryDeser.xReadRefNoSer(br, pack);
-      }else{
+      } else if (typeWrap.nullable) {
         fieldValue = pack.foryDeser.xReadRefWithSer(br, ser, pack);
+      } else {
+        fieldValue = ser.read(br, -1, pack);
       }
       assert(fieldSpec.setter != null);
       fieldSpec.setter!(obj, fieldValue);
-      if (hasGenericsParam){
+      if (hasGenericsParam) {
         pack.typeWrapStack.pop();
       }
     }
@@ -129,55 +140,62 @@ final class ClassSerializer extends 
CustomSerializer<Object>{
 
   @override
   void write(ByteWriter bw, Object v, SerializerPack pack) {
-    if (!_fieldsSersComputed){
+    if (!_fieldsSersComputed) {
       pack.xtypeResolver.setSersForTypeWrap(_fieldTypeWraps);
       _fieldsSersComputed = true;
     }
-    if (!_hashComputed){
-      var pair = pack.structHashResolver.computeHash(_fields, 
pack.getTagByDartType);
+    if (!_compatible && !_hashComputed) {
+      var pair =
+          pack.structHashResolver.computeHash(_fields, pack.getTagByDartType);
       _fromForyHash = pair.fromForyHash;
       _toForyHash = pair.toForyHash;
       _hashComputed = true;
     }
-    bw.writeInt32(_toForyHash);
+    if (!_compatible) {
+      bw.writeInt32(_toForyHash);
+    }
     for (int i = 0; i < _fields.length; ++i) {
       FieldSpec fieldSpec = _fields[i];
       if (!fieldSpec.includeToFory) continue;
       TypeSpecWrap typeWrap = _fieldTypeWraps[i];
       bool hasGenericsParam = typeWrap.hasGenericsParam;
-      if (hasGenericsParam){
+      if (hasGenericsParam) {
         pack.typeWrapStack.push(typeWrap);
       }
       Object? fieldValue = fieldSpec.getter!(v);
       Serializer? ser = typeWrap.ser;
       if (ser == null) {
         pack.forySer.xWriteRefNoSer(bw, fieldValue, pack);
-      }else{
+      } else if (typeWrap.nullable) {
         pack.forySer.xWriteRefWithSer(bw, ser, fieldValue, pack);
+      } else {
+        ser.write(bw, fieldValue!, pack);
       }
-      if (hasGenericsParam){
+      if (hasGenericsParam) {
         pack.typeWrapStack.pop();
       }
     }
   }
 
-  Object _byParameterizedCons(ByteReader br, int refId, DeserializerPack pack){
+  Object _byParameterizedCons(ByteReader br, int refId, DeserializerPack pack) 
{
     List<Object?> args = List.filled(_fields.length, null);
-    for (int i = 0; i < _fields.length; ++i){
+    for (int i = 0; i < _fields.length; ++i) {
       FieldSpec fieldSpec = _fields[i];
       if (!fieldSpec.includeFromFory) continue;
       TypeSpecWrap typeWrap = _fieldTypeWraps[i];
       bool hasGenericsParam = typeWrap.hasGenericsParam;
-      if (hasGenericsParam){
+      if (hasGenericsParam) {
         pack.typeWrapStack.push(typeWrap);
       }
       Serializer? ser = typeWrap.ser;
       if (ser == null) {
         args[i] = pack.foryDeser.xReadRefNoSer(br, pack);
-      }else{
+      } else if (typeWrap.nullable) {
         args[i] = pack.foryDeser.xReadRefWithSer(br, ser, pack);
+      } else {
+        args[i] = ser.read(br, -1, pack);
       }
-      if (hasGenericsParam){
+      if (hasGenericsParam) {
         pack.typeWrapStack.pop();
       }
     }
diff --git 
a/dart/packages/fory/lib/src/serializer/collection/iterable_serializer.dart 
b/dart/packages/fory/lib/src/serializer/collection/iterable_serializer.dart
index b04ac736b..53e114535 100644
--- a/dart/packages/fory/lib/src/serializer/collection/iterable_serializer.dart
+++ b/dart/packages/fory/lib/src/serializer/collection/iterable_serializer.dart
@@ -17,46 +17,204 @@
  * under the License.
  */
 
+import 'package:fory/src/const/ref_flag.dart';
 import 'package:fory/src/memory/byte_writer.dart';
 import 'package:fory/src/meta/spec_wraps/type_spec_wrap.dart';
 import 'package:fory/src/serializer/serializer.dart';
 import 'package:fory/src/serializer_pack.dart';
 
 abstract base class IterableSerializer extends Serializer<Iterable> {
+  static const int trackingRefFlag = 0x01;
+  static const int hasNullFlag = 0x02;
+  static const int isDeclElementTypeFlag = 0x04;
+  static const int isSameTypeFlag = 0x08;
+
+  static const int declSameTypeTrackingRef =
+      isDeclElementTypeFlag | isSameTypeFlag | trackingRefFlag;
+  static const int declSameTypeHasNull =
+      isDeclElementTypeFlag | isSameTypeFlag | hasNullFlag;
+  static const int declSameTypeNotHasNull =
+      isDeclElementTypeFlag | isSameTypeFlag;
 
   const IterableSerializer(super.objType, super.writeRef);
 
   @override
   void write(ByteWriter bw, Iterable v, SerializerPack pack) {
-    bw.writeVarUint32Small7(v.length);
-    TypeSpecWrap? elemWrap = pack.typeWrapStack.peek?.param0;
-    if (elemWrap == null){
-      for (var o in v) {
-        pack.forySer.xWriteRefNoSer(bw, o, pack);
-      }
+    final int len = v.length;
+    bw.writeVarUint32Small7(len);
+    if (len == 0) {
       return;
     }
-    if (elemWrap.hasGenericsParam){
+    TypeSpecWrap? elemWrap = pack.typeWrapStack.peek?.param0;
+    final ({int flags, Serializer? ser}) header =
+        _writeElementsHeader(bw, v, elemWrap, pack);
+    if (elemWrap != null && elemWrap.hasGenericsParam) {
       pack.typeWrapStack.push(elemWrap);
     }
-    if (!elemWrap.certainForSer){
-      for (var o in v) {
-        pack.forySer.xWriteRefNoSer(bw, o, pack);
+
+    int flags = header.flags;
+    Serializer? ser = header.ser;
+    if ((flags & isSameTypeFlag) == isSameTypeFlag && ser != null) {
+      if ((flags & trackingRefFlag) == trackingRefFlag) {
+        for (Object? elem in v) {
+          pack.forySer.xWriteRefWithSer(bw, ser, elem, pack);
+        }
+      } else {
+        if ((flags & hasNullFlag) == hasNullFlag) {
+          for (Object? elem in v) {
+            if (elem == null) {
+              bw.writeInt8(RefFlag.NULL.id);
+            } else {
+              bw.writeInt8(RefFlag.UNTRACKED_NOT_NULL.id);
+              ser.write(bw, elem, pack);
+            }
+          }
+        } else {
+          for (Object? elem in v) {
+            ser.write(bw, elem as Object, pack);
+          }
+        }
       }
-    }else {
-      Serializer? ser = elemWrap.ser;
-      if (ser == null){
-        for (var o in v) {
-          pack.forySer.xWriteRefNoSer(bw, o, pack);
+    } else {
+      if ((flags & trackingRefFlag) == trackingRefFlag) {
+        for (Object? elem in v) {
+          pack.forySer.xWriteRefNoSer(bw, elem, pack);
         }
-      }else{
-        for (var o in v) {
-          pack.forySer.xWriteRefWithSer(bw, ser, o, pack);
+      } else {
+        if ((flags & hasNullFlag) == hasNullFlag) {
+          for (Object? elem in v) {
+            if (elem == null) {
+              bw.writeInt8(RefFlag.NULL.id);
+            } else {
+              bw.writeInt8(RefFlag.UNTRACKED_NOT_NULL.id);
+              pack.forySer.xWriteNonRefNoSer(bw, elem, pack);
+            }
+          }
+        } else {
+          for (Object? elem in v) {
+            pack.forySer.xWriteNonRefNoSer(bw, elem as Object, pack);
+          }
         }
       }
     }
-    if (elemWrap.hasGenericsParam){
+
+    if (elemWrap != null && elemWrap.hasGenericsParam) {
       pack.typeWrapStack.pop();
     }
   }
-}
\ No newline at end of file
+
+  ({int flags, Serializer? ser}) _writeElementsHeader(ByteWriter bw,
+      Iterable value, TypeSpecWrap? elemWrap, SerializerPack pack) {
+    if (elemWrap != null) {
+      if (elemWrap.certainForSer && elemWrap.ser != null) {
+        Serializer ser = elemWrap.ser!;
+        if (ser.writeRef) {
+          bw.writeUint8(declSameTypeTrackingRef);
+          return (flags: declSameTypeTrackingRef, ser: ser);
+        }
+        int flags =
+            _containsNull(value) ? declSameTypeHasNull : 
declSameTypeNotHasNull;
+        bw.writeUint8(flags);
+        return (flags: flags, ser: ser);
+      }
+      bool trackingRef = elemWrap.ser?.writeRef ?? _isRefTrackingEnabled(pack);
+      if (trackingRef) {
+        return _writeTypeHeader(bw, value, elemWrap, pack);
+      }
+      return _writeTypeNullabilityHeader(bw, value, elemWrap, pack);
+    }
+
+    if (_isRefTrackingEnabled(pack)) {
+      return _writeTypeHeader(bw, value, null, pack);
+    }
+    return _writeTypeNullabilityHeader(bw, value, null, pack);
+  }
+
+  ({int flags, Serializer? ser}) _writeTypeHeader(ByteWriter bw, Iterable 
value,
+      TypeSpecWrap? declareWrap, SerializerPack pack) {
+    bool hasDifferentClass = false;
+    Object? firstNonNull;
+    Type? elemType;
+    for (Object? elem in value) {
+      if (elem == null) {
+        continue;
+      }
+      if (elemType == null) {
+        firstNonNull = elem;
+        elemType = elem.runtimeType;
+      } else if (elem.runtimeType != elemType) {
+        hasDifferentClass = true;
+        break;
+      }
+    }
+    if (hasDifferentClass || firstNonNull == null) {
+      bw.writeUint8(trackingRefFlag);
+      return (flags: trackingRefFlag, ser: null);
+    }
+
+    int flags = trackingRefFlag | isSameTypeFlag;
+    Serializer? declaredSer = declareWrap?.ser;
+    if (declareWrap != null &&
+        declaredSer != null &&
+        elemType == declareWrap.type) {
+      flags |= isDeclElementTypeFlag;
+      bw.writeUint8(flags);
+      return (flags: flags, ser: declaredSer);
+    }
+    bw.writeUint8(flags);
+    final typeInfo =
+        pack.xtypeResolver.writeGetTypeInfo(bw, firstNonNull, pack);
+    return (flags: flags, ser: typeInfo.ser);
+  }
+
+  ({int flags, Serializer? ser}) _writeTypeNullabilityHeader(ByteWriter bw,
+      Iterable value, TypeSpecWrap? declareWrap, SerializerPack pack) {
+    int flags = 0;
+    bool hasDifferentClass = false;
+    Object? firstNonNull;
+    Type? elemType;
+    for (Object? elem in value) {
+      if (elem == null) {
+        flags |= hasNullFlag;
+        continue;
+      }
+      if (elemType == null) {
+        firstNonNull = elem;
+        elemType = elem.runtimeType;
+      } else if (!hasDifferentClass && elem.runtimeType != elemType) {
+        hasDifferentClass = true;
+      }
+    }
+    if (hasDifferentClass || firstNonNull == null) {
+      bw.writeUint8(flags);
+      return (flags: flags, ser: null);
+    }
+
+    flags |= isSameTypeFlag;
+    Serializer? declaredSer = declareWrap?.ser;
+    if (declareWrap != null &&
+        declaredSer != null &&
+        elemType == declareWrap.type) {
+      flags |= isDeclElementTypeFlag;
+      bw.writeUint8(flags);
+      return (flags: flags, ser: declaredSer);
+    }
+    bw.writeUint8(flags);
+    final typeInfo =
+        pack.xtypeResolver.writeGetTypeInfo(bw, firstNonNull, pack);
+    return (flags: flags, ser: typeInfo.ser);
+  }
+
+  bool _isRefTrackingEnabled(SerializerPack pack) {
+    return !identical(pack.refResolver, pack.noRefResolver);
+  }
+
+  bool _containsNull(Iterable value) {
+    for (Object? elem in value) {
+      if (elem == null) {
+        return true;
+      }
+    }
+    return false;
+  }
+}
diff --git 
a/dart/packages/fory/lib/src/serializer/collection/list/list_serializer.dart 
b/dart/packages/fory/lib/src/serializer/collection/list/list_serializer.dart
index 71d0eefa8..c54d05349 100644
--- a/dart/packages/fory/lib/src/serializer/collection/list/list_serializer.dart
+++ b/dart/packages/fory/lib/src/serializer/collection/list/list_serializer.dart
@@ -17,6 +17,7 @@
  * under the License.
  */
 
+import 'package:fory/src/const/ref_flag.dart';
 import 'package:fory/src/const/types.dart';
 import 'package:fory/src/deserializer_pack.dart';
 import 'package:fory/src/memory/byte_reader.dart';
@@ -25,9 +26,8 @@ import 
'package:fory/src/serializer/collection/iterable_serializer.dart';
 import 'package:fory/src/serializer/serializer.dart';
 
 abstract base class ListSerializer extends IterableSerializer {
+  const ListSerializer(bool writeRef) : super(ObjType.LIST, writeRef);
 
-  const ListSerializer(bool writeRef): super(ObjType.LIST, writeRef);
-  
   List newList(int size, bool nullable);
 
   @override
@@ -38,41 +38,76 @@ abstract base class ListSerializer extends 
IterableSerializer {
       num,
       elemWrap == null || elemWrap.nullable,
     );
-    if (writeRef){
+    if (writeRef) {
       pack.refResolver.setRefTheLatestId(list);
     }
-    if (elemWrap == null){
-      for (int i = 0; i < num; ++i) {
-        Object? o = pack.foryDeser.xReadRefNoSer(br, pack);
-        list[i] = o;
-      }
+    if (num == 0) {
       return list;
     }
-    if (elemWrap.hasGenericsParam){
+
+    int flags = br.readUint8();
+    bool hasGenericsParam = elemWrap != null && elemWrap.hasGenericsParam;
+    if (hasGenericsParam) {
       pack.typeWrapStack.push(elemWrap);
     }
-    if (!elemWrap.certainForSer){
-      for (int i = 0; i < num; ++i) {
-        Object? o = pack.foryDeser.xReadRefNoSer(br, pack);
-        list[i] = o;
+
+    if ((flags & IterableSerializer.isSameTypeFlag) ==
+        IterableSerializer.isSameTypeFlag) {
+      Serializer? ser;
+      bool isDeclElemType =
+          (flags & IterableSerializer.isDeclElementTypeFlag) ==
+              IterableSerializer.isDeclElementTypeFlag;
+      if (isDeclElemType) {
+        ser = elemWrap?.ser;
+      }
+      if (ser == null) {
+        ser = pack.xtypeResolver.readTypeInfo(br).ser;
       }
-    }else {
-      Serializer? ser = elemWrap.ser;
-      if (ser == null){
+
+      if ((flags & IterableSerializer.trackingRefFlag) ==
+          IterableSerializer.trackingRefFlag) {
+        for (int i = 0; i < num; ++i) {
+          list[i] = pack.foryDeser.xReadRefWithSer(br, ser, pack);
+        }
+      } else if ((flags & IterableSerializer.hasNullFlag) ==
+          IterableSerializer.hasNullFlag) {
         for (int i = 0; i < num; ++i) {
-          Object? o = pack.foryDeser.xReadRefNoSer(br, pack);
-          list[i] = o;
+          if (br.readInt8() == RefFlag.NULL.id) {
+            list[i] = null;
+          } else {
+            list[i] = ser.read(br, -1, pack);
+          }
         }
-      }else{
+      } else {
         for (int i = 0; i < num; ++i) {
-          Object? o = pack.foryDeser.xReadRefWithSer(br, ser, pack);
-          list[i] = o;
+          list[i] = ser.read(br, -1, pack);
+        }
+      }
+    } else {
+      if ((flags & IterableSerializer.trackingRefFlag) ==
+          IterableSerializer.trackingRefFlag) {
+        for (int i = 0; i < num; ++i) {
+          list[i] = pack.foryDeser.xReadRefNoSer(br, pack);
+        }
+      } else if ((flags & IterableSerializer.hasNullFlag) ==
+          IterableSerializer.hasNullFlag) {
+        for (int i = 0; i < num; ++i) {
+          if (br.readInt8() == RefFlag.NULL.id) {
+            list[i] = null;
+          } else {
+            list[i] = pack.foryDeser.xReadNonRefNoSer(br, pack);
+          }
+        }
+      } else {
+        for (int i = 0; i < num; ++i) {
+          list[i] = pack.foryDeser.xReadNonRefNoSer(br, pack);
         }
       }
     }
-    if (elemWrap.hasGenericsParam){
+
+    if (hasGenericsParam) {
       pack.typeWrapStack.pop();
     }
     return list;
   }
-}
\ No newline at end of file
+}
diff --git 
a/dart/packages/fory/lib/src/serializer/collection/map/map_serializer.dart 
b/dart/packages/fory/lib/src/serializer/collection/map/map_serializer.dart
index af3a3ec04..8b351720f 100644
--- a/dart/packages/fory/lib/src/serializer/collection/map/map_serializer.dart
+++ b/dart/packages/fory/lib/src/serializer/collection/map/map_serializer.dart
@@ -18,169 +18,402 @@
  */
 
 import 'package:fory/src/deserializer_pack.dart';
-import 'package:fory/src/dev_annotation/optimize.dart';
 import 'package:fory/src/meta/spec_wraps/type_spec_wrap.dart';
-import 'package:fory/src/collection/stack.dart';
 import 'package:fory/src/const/types.dart';
 import 'package:fory/src/memory/byte_reader.dart';
 import 'package:fory/src/memory/byte_writer.dart';
 import 'package:fory/src/serializer_pack.dart';
 import 'package:fory/src/serializer/serializer.dart';
 
-abstract base class MapSerializer<T extends Map<Object?,Object?>> extends 
Serializer<Map<Object?,Object?>> {
+abstract base class MapSerializer<T extends Map<Object?, Object?>>
+    extends Serializer<Map<Object?, Object?>> {
+  static const int _maxChunkSize = 255;
 
-  const MapSerializer(bool writeRef): super(ObjType.MAP, writeRef);
+  static const int _trackingKeyRef = 0x01;
+  static const int _keyHasNull = 0x02;
+  static const int _keyDeclType = 0x04;
+  static const int _trackingValueRef = 0x08;
+  static const int _valueHasNull = 0x10;
+  static const int _valueDeclType = 0x20;
+
+  static const int _kvNull = _keyHasNull | _valueHasNull;
+  static const int _nullKeyValueDeclType = _keyHasNull | _valueDeclType;
+  static const int _nullKeyValueDeclTypeTrackingRef =
+      _keyHasNull | _valueDeclType | _trackingValueRef;
+  static const int _nullValueKeyDeclType = _valueHasNull | _keyDeclType;
+  static const int _nullValueKeyDeclTypeTrackingRef =
+      _valueHasNull | _keyDeclType | _trackingKeyRef;
+
+  const MapSerializer(bool writeRef) : super(ObjType.MAP, writeRef);
 
   T newMap(int size);
 
   @override
   T read(ByteReader br, int refId, DeserializerPack pack) {
-    int len = br.readVarUint32Small7();
-    T map = newMap(len);
-    if (writeRef){
+    int remaining = br.readVarUint32Small7();
+    T map = newMap(remaining);
+    if (writeRef) {
       pack.refResolver.setRefTheLatestId(map);
     }
-    TypeSpecWrap? typeWrap = pack.typeWrapStack.peek;
-    if (typeWrap == null){
-      // Traverse entries
-      for (int i = 0; i < len; ++i) {
-        Object? key = pack.foryDeser.xReadRefNoSer(br, pack);
-        Object? value = pack.foryDeser.xReadRefNoSer(br, pack);
-        map[key] = value;
-      }
+    if (remaining == 0) {
       return map;
     }
-    Stack<TypeSpecWrap> typeWrapStack = pack.typeWrapStack;
-    TypeSpecWrap keyWrap = typeWrap.param0!;
-    TypeSpecWrap valueWrap = typeWrap.param1!;
-    Serializer? keySer = keyWrap.ser;
-    Serializer? valueSer = valueWrap.ser;
-
-    if (!keyWrap.hasGenericsParam && !valueWrap.hasGenericsParam){
-      // Traverse entries
-      for (int i = 0; i < len; ++i) {
-        Object? key = _readWithNullableSer(br, keySer, pack);
-        Object? value = _readWithNullableSer(br, valueSer, pack);
+
+    TypeSpecWrap? mapWrap = pack.typeWrapStack.peek;
+    TypeSpecWrap? keyWrap = mapWrap?.param0;
+    TypeSpecWrap? valueWrap = mapWrap?.param1;
+
+    while (remaining > 0) {
+      int chunkHeader = br.readUint8();
+      bool keyHasNull = (chunkHeader & _keyHasNull) != 0;
+      bool valueHasNull = (chunkHeader & _valueHasNull) != 0;
+      if (keyHasNull || valueHasNull) {
+        Object? key;
+        Object? value;
+        if (!keyHasNull) {
+          key = _readNullChunkKey(br, chunkHeader, keyWrap, pack);
+          value = null;
+        } else if (!valueHasNull) {
+          key = null;
+          value = _readNullChunkValue(br, chunkHeader, valueWrap, pack);
+        } else {
+          key = null;
+          value = null;
+        }
         map[key] = value;
+        --remaining;
+        continue;
       }
-      return map;
-    }
-    if (!keyWrap.hasGenericsParam && valueWrap.hasGenericsParam){
-      // Traverse entries
-      for (int i = 0; i < len; ++i) {
-        Object? key = _readWithNullableSer(br, keySer, pack);
-        typeWrapStack.push(valueWrap);
-        Object? value = _readWithNullableSer(br, valueSer, pack);
-        typeWrapStack.pop();
-        map[key] = value;
+
+      bool keyTrackRef = (chunkHeader & _trackingKeyRef) != 0;
+      bool valueTrackRef = (chunkHeader & _trackingValueRef) != 0;
+      bool keyDeclaredType = (chunkHeader & _keyDeclType) != 0;
+      bool valueDeclaredType = (chunkHeader & _valueDeclType) != 0;
+      int chunkSize = br.readUint8();
+
+      Serializer keySer;
+      if (keyDeclaredType && keyWrap?.ser != null) {
+        keySer = keyWrap!.ser!;
+      } else {
+        keySer = pack.xtypeResolver.readTypeInfo(br).ser;
+      }
+      Serializer valueSer;
+      if (valueDeclaredType && valueWrap?.ser != null) {
+        valueSer = valueWrap!.ser!;
+      } else {
+        valueSer = pack.xtypeResolver.readTypeInfo(br).ser;
       }
-      return map;
-    }
 
-    if (keyWrap.hasGenericsParam && !valueWrap.hasGenericsParam){
-      // Traverse entries
-      for (int i = 0; i < len; ++i) {
-        typeWrapStack.push(keyWrap);
-        Object? key = _readWithNullableSer(br, keySer, pack);
-        typeWrapStack.pop();
-        Object? value = _readWithNullableSer(br, valueSer, pack);
+      for (int i = 0; i < chunkSize; ++i) {
+        Object? key = _readWithSer(br, keySer, keyTrackRef, pack, keyWrap);
+        Object? value =
+            _readWithSer(br, valueSer, valueTrackRef, pack, valueWrap);
         map[key] = value;
       }
-      return map;
-    }
-
-    for (int i = 0; i < len; ++i) {
-      typeWrapStack.push(keyWrap);
-      Object? key = _readWithNullableSer(br, keySer, pack);
-      typeWrapStack.changeTop(valueWrap);
-      Object? value = _readWithNullableSer(br, valueSer, pack);
-      typeWrapStack.pop();
-      map[key] = value;
+      remaining -= chunkSize;
     }
     return map;
   }
 
-  /// This code may look a bit lengthy, but to avoid unnecessary checks 
multiple times in the loop
-  /// (since it only needs to be done once), the outer judgment cases are 
separated, making the code look a bit long
   @override
   void write(ByteWriter bw, covariant T v, SerializerPack pack) {
-    bw.writeVarUint32Small7(v.length);
-    TypeSpecWrap? typeWrap = pack.typeWrapStack.peek;
-    if (typeWrap == null){
-      // Traverse entries
-      for (var entry in v.entries) {
-        Object? key = entry.key;
-        Object? value = entry.value;
-        pack.forySer.xWriteRefNoSer(bw, key, pack);
-        pack.forySer.xWriteRefNoSer(bw, value, pack);
-      }
+    int mapSize = v.length;
+    bw.writeVarUint32Small7(mapSize);
+    if (mapSize == 0) {
       return;
     }
-    var typeWrapStack = pack.typeWrapStack;
-    TypeSpecWrap keyWrap = typeWrap.param0!;
-    TypeSpecWrap valueWrap = typeWrap.param1!;
-    Serializer? keySer = keyWrap.ser;
-    Serializer? valueSer = valueWrap.ser;
 
-    if (!keyWrap.hasGenericsParam && !valueWrap.hasGenericsParam){
-      // Traverse entries
-      for (var entry in v.entries) {
-        Object? key = entry.key;
-        Object? value = entry.value;
-        _writeWithNullableSer(bw, key, keySer, pack);
-        _writeWithNullableSer(bw, value, valueSer, pack);
-      }
+    TypeSpecWrap? mapWrap = pack.typeWrapStack.peek;
+    TypeSpecWrap? keyWrap = mapWrap?.param0;
+    TypeSpecWrap? valueWrap = mapWrap?.param1;
+
+    Iterator<MapEntry<Object?, Object?>> iterator = v.entries.iterator;
+    if (!iterator.moveNext()) {
       return;
     }
+    MapEntry<Object?, Object?>? entry = iterator.current;
 
-    if (keyWrap.hasGenericsParam && !valueWrap.hasGenericsParam){
-      // Traverse entries
-      for (var entry in v.entries) {
+    while (entry != null) {
+      while (entry != null) {
         Object? key = entry.key;
         Object? value = entry.value;
-        typeWrapStack.push(keyWrap);
-        _writeWithNullableSer(bw, key, keySer, pack);
-        typeWrapStack.pop();
-        _writeWithNullableSer(bw, value, valueSer, pack);
+        if (key != null && value != null) {
+          break;
+        }
+        _writeNullChunk(bw, key, value, keyWrap, valueWrap, pack);
+        if (iterator.moveNext()) {
+          entry = iterator.current;
+        } else {
+          entry = null;
+        }
       }
-      return;
+      if (entry == null) {
+        break;
+      }
+      entry = _writeNonNullChunk(bw, entry, iterator, keyWrap, valueWrap, 
pack);
     }
+  }
 
-    if (!keyWrap.hasGenericsParam && valueWrap.hasGenericsParam){
-      // Traverse entries
-      for (var entry in v.entries) {
-        Object? key = entry.key;
-        Object? value = entry.value;
-        _writeWithNullableSer(bw, key, keySer, pack);
-        typeWrapStack.push(valueWrap);
-        _writeWithNullableSer(bw, value, valueSer, pack);
-        typeWrapStack.pop();
+  MapEntry<Object?, Object?>? _writeNonNullChunk(
+    ByteWriter bw,
+    MapEntry<Object?, Object?> entry,
+    Iterator<MapEntry<Object?, Object?>> iterator,
+    TypeSpecWrap? keyWrap,
+    TypeSpecWrap? valueWrap,
+    SerializerPack pack,
+  ) {
+    Object key0 = entry.key as Object;
+    Object value0 = entry.value as Object;
+    Type keyType = key0.runtimeType;
+    Type valueType = value0.runtimeType;
+
+    int chunkHeader = 0;
+    ByteWriter chunkWriter = ByteWriter();
+    Serializer keySer;
+    Serializer valueSer;
+
+    if (keyWrap != null && keyWrap.certainForSer && keyWrap.ser != null) {
+      chunkHeader |= _keyDeclType;
+      keySer = keyWrap.ser!;
+    } else {
+      final typeInfo =
+          pack.xtypeResolver.writeGetTypeInfo(chunkWriter, key0, pack);
+      keySer = typeInfo.ser;
+    }
+    if (valueWrap != null && valueWrap.certainForSer && valueWrap.ser != null) 
{
+      chunkHeader |= _valueDeclType;
+      valueSer = valueWrap.ser!;
+    } else {
+      final typeInfo =
+          pack.xtypeResolver.writeGetTypeInfo(chunkWriter, value0, pack);
+      valueSer = typeInfo.ser;
+    }
+
+    bool trackKeyRef = keySer.writeRef;
+    bool trackValueRef = valueSer.writeRef;
+    if (trackKeyRef) {
+      chunkHeader |= _trackingKeyRef;
+    }
+    if (trackValueRef) {
+      chunkHeader |= _trackingValueRef;
+    }
+
+    int chunkSize = 0;
+    MapEntry<Object?, Object?>? current = entry;
+    while (current != null) {
+      Object? key = current.key;
+      Object? value = current.value;
+      if (key == null ||
+          value == null ||
+          key.runtimeType != keyType ||
+          value.runtimeType != valueType) {
+        break;
+      }
+      _writeWithSer(chunkWriter, key, keySer, trackKeyRef, pack, keyWrap);
+      _writeWithSer(
+          chunkWriter, value, valueSer, trackValueRef, pack, valueWrap);
+      ++chunkSize;
+      if (iterator.moveNext()) {
+        current = iterator.current;
+      } else {
+        current = null;
+        break;
+      }
+      if (chunkSize == _maxChunkSize) {
+        break;
       }
+    }
+
+    bw.writeUint8(chunkHeader);
+    bw.writeUint8(chunkSize);
+    bw.writeBytes(chunkWriter.takeBytes());
+    return current;
+  }
+
+  void _writeNullChunk(
+    ByteWriter bw,
+    Object? key,
+    Object? value,
+    TypeSpecWrap? keyWrap,
+    TypeSpecWrap? valueWrap,
+    SerializerPack pack,
+  ) {
+    if (key != null) {
+      _writeNullValueChunk(bw, key, keyWrap, pack);
+      return;
+    }
+    if (value != null) {
+      _writeNullKeyChunk(bw, value, valueWrap, pack);
+      return;
+    }
+    bw.writeUint8(_kvNull);
+  }
+
+  void _writeNullValueChunk(
+    ByteWriter bw,
+    Object key,
+    TypeSpecWrap? keyWrap,
+    SerializerPack pack,
+  ) {
+    Serializer? keySer = keyWrap?.ser;
+    if (keyWrap != null && keyWrap.certainForSer && keySer != null) {
+      bool trackingRef = keySer.writeRef;
+      bw.writeUint8(trackingRef
+          ? _nullValueKeyDeclTypeTrackingRef
+          : _nullValueKeyDeclType);
+      _writeWithSer(bw, key, keySer, trackingRef, pack, keyWrap);
       return;
     }
-    // Traverse entries
-    for (var entry in v.entries) {
-      Object? key = entry.key;
-      Object? value = entry.value;
-      typeWrapStack.push(keyWrap);
-      _writeWithNullableSer(bw, key, keySer, pack);
-      typeWrapStack.changeTop(valueWrap);
-      _writeWithNullableSer(bw, value, valueSer, pack);
-      typeWrapStack.pop();
+    bool trackingRef = keyWrap == null
+        ? true
+        : (keySer?.writeRef ?? _isRefTrackingEnabled(pack));
+    bw.writeUint8(_valueHasNull | (trackingRef ? _trackingKeyRef : 0));
+    _writeWithDynamic(bw, key, trackingRef, pack, keyWrap);
+  }
+
+  void _writeNullKeyChunk(
+    ByteWriter bw,
+    Object value,
+    TypeSpecWrap? valueWrap,
+    SerializerPack pack,
+  ) {
+    Serializer? valueSer = valueWrap?.ser;
+    if (valueWrap != null && valueWrap.certainForSer && valueSer != null) {
+      bool trackingRef = valueSer.writeRef;
+      bw.writeUint8(trackingRef
+          ? _nullKeyValueDeclTypeTrackingRef
+          : _nullKeyValueDeclType);
+      _writeWithSer(bw, value, valueSer, trackingRef, pack, valueWrap);
+      return;
+    }
+    bool trackingRef = valueWrap == null
+        ? true
+        : (valueSer?.writeRef ?? _isRefTrackingEnabled(pack));
+    bw.writeUint8(_keyHasNull | (trackingRef ? _trackingValueRef : 0));
+    _writeWithDynamic(bw, value, trackingRef, pack, valueWrap);
+  }
+
+  Object? _readNullChunkKey(
+    ByteReader br,
+    int chunkHeader,
+    TypeSpecWrap? keyWrap,
+    DeserializerPack pack,
+  ) {
+    bool trackRef = (chunkHeader & _trackingKeyRef) != 0;
+    bool keyDeclaredType = (chunkHeader & _keyDeclType) != 0;
+    if (keyDeclaredType && keyWrap?.ser != null) {
+      return _readWithSer(br, keyWrap!.ser!, trackRef, pack, keyWrap);
     }
+    return _readWithDynamic(br, trackRef, pack, keyWrap);
   }
 
-  @inline
-  void _writeWithNullableSer(ByteWriter bw, Object? v, Serializer? ser, 
SerializerPack pack){
-    ser == null ?
-    pack.forySer.xWriteRefNoSer(bw, v, pack) :
-    pack.forySer.xWriteRefWithSer(bw, ser, v, pack);
+  Object? _readNullChunkValue(
+    ByteReader br,
+    int chunkHeader,
+    TypeSpecWrap? valueWrap,
+    DeserializerPack pack,
+  ) {
+    bool trackRef = (chunkHeader & _trackingValueRef) != 0;
+    bool valueDeclaredType = (chunkHeader & _valueDeclType) != 0;
+    if (valueDeclaredType && valueWrap?.ser != null) {
+      return _readWithSer(br, valueWrap!.ser!, trackRef, pack, valueWrap);
+    }
+    return _readWithDynamic(br, trackRef, pack, valueWrap);
+  }
+
+  void _writeWithSer(
+    ByteWriter bw,
+    Object value,
+    Serializer ser,
+    bool trackRef,
+    SerializerPack pack,
+    TypeSpecWrap? wrap,
+  ) {
+    bool pushed = _pushWrapForWrite(wrap, pack);
+    if (trackRef) {
+      pack.forySer.xWriteRefWithSer(bw, ser, value, pack);
+    } else {
+      ser.write(bw, value, pack);
+    }
+    if (pushed) {
+      pack.typeWrapStack.pop();
+    }
+  }
+
+  Object? _readWithSer(
+    ByteReader br,
+    Serializer ser,
+    bool trackRef,
+    DeserializerPack pack,
+    TypeSpecWrap? wrap,
+  ) {
+    bool pushed = _pushWrapForRead(wrap, pack);
+    Object? value;
+    if (trackRef) {
+      value = pack.foryDeser.xReadRefWithSer(br, ser, pack);
+    } else {
+      value = ser.read(br, -1, pack);
+    }
+    if (pushed) {
+      pack.typeWrapStack.pop();
+    }
+    return value;
+  }
+
+  void _writeWithDynamic(
+    ByteWriter bw,
+    Object value,
+    bool trackRef,
+    SerializerPack pack,
+    TypeSpecWrap? wrap,
+  ) {
+    bool pushed = _pushWrapForWrite(wrap, pack);
+    if (trackRef) {
+      pack.forySer.xWriteRefNoSer(bw, value, pack);
+    } else {
+      pack.forySer.xWriteNonRefNoSer(bw, value, pack);
+    }
+    if (pushed) {
+      pack.typeWrapStack.pop();
+    }
+  }
+
+  Object _readWithDynamic(
+    ByteReader br,
+    bool trackRef,
+    DeserializerPack pack,
+    TypeSpecWrap? wrap,
+  ) {
+    bool pushed = _pushWrapForRead(wrap, pack);
+    Object value;
+    if (trackRef) {
+      value = pack.foryDeser.xReadRefNoSer(br, pack) as Object;
+    } else {
+      value = pack.foryDeser.xReadNonRefNoSer(br, pack);
+    }
+    if (pushed) {
+      pack.typeWrapStack.pop();
+    }
+    return value;
+  }
+
+  bool _pushWrapForWrite(TypeSpecWrap? wrap, SerializerPack pack) {
+    if (wrap != null && wrap.hasGenericsParam) {
+      pack.typeWrapStack.push(wrap);
+      return true;
+    }
+    return false;
+  }
+
+  bool _pushWrapForRead(TypeSpecWrap? wrap, DeserializerPack pack) {
+    if (wrap != null && wrap.hasGenericsParam) {
+      pack.typeWrapStack.push(wrap);
+      return true;
+    }
+    return false;
   }
 
-  @inline
-  Object? _readWithNullableSer(ByteReader br, Serializer? ser, 
DeserializerPack pack){
-    return ser == null ?
-    pack.foryDeser.xReadRefNoSer(br, pack) :
-    pack.foryDeser.xReadRefWithSer(br, ser, pack);
+  bool _isRefTrackingEnabled(SerializerPack pack) {
+    return !identical(pack.refResolver, pack.noRefResolver);
   }
 }
diff --git 
a/dart/packages/fory/lib/src/serializer/collection/set/set_serializer.dart 
b/dart/packages/fory/lib/src/serializer/collection/set/set_serializer.dart
index 06428ed73..ad904d14e 100644
--- a/dart/packages/fory/lib/src/serializer/collection/set/set_serializer.dart
+++ b/dart/packages/fory/lib/src/serializer/collection/set/set_serializer.dart
@@ -25,6 +25,7 @@
 /// we still need to implement this separately, which may introduce duplicate 
code.
 library;
 
+import 'package:fory/src/const/ref_flag.dart';
 import 'package:fory/src/const/types.dart';
 import 'package:fory/src/deserializer_pack.dart';
 import 'package:fory/src/memory/byte_reader.dart';
@@ -33,9 +34,8 @@ import 
'package:fory/src/serializer/collection/iterable_serializer.dart';
 import 'package:fory/src/serializer/serializer.dart';
 
 abstract base class SetSerializer extends IterableSerializer {
+  const SetSerializer(bool writeRef) : super(ObjType.SET, writeRef);
 
-  const SetSerializer(bool writeRef): super(ObjType.SET, writeRef);
-  
   Set newSet(bool nullable);
 
   @override
@@ -45,39 +45,74 @@ abstract base class SetSerializer extends 
IterableSerializer {
     Set set = newSet(
       elemWrap == null || elemWrap.nullable,
     );
-    if (writeRef){
+    if (writeRef) {
       pack.refResolver.setRefTheLatestId(set);
     }
-    if (elemWrap == null){
-      for (int i = 0; i < num; ++i) {
-        Object? o = pack.foryDeser.xReadRefNoSer(br, pack);
-        set.add(o);
-      }
+    if (num == 0) {
       return set;
     }
-    if (elemWrap.hasGenericsParam){
+
+    int flags = br.readUint8();
+    bool hasGenericsParam = elemWrap != null && elemWrap.hasGenericsParam;
+    if (hasGenericsParam) {
       pack.typeWrapStack.push(elemWrap);
     }
-    if (!elemWrap.certainForSer){
-      for (int i = 0; i < num; ++i) {
-        Object? o = pack.foryDeser.xReadRefNoSer(br, pack);
-        set.add(o);
+
+    if ((flags & IterableSerializer.isSameTypeFlag) ==
+        IterableSerializer.isSameTypeFlag) {
+      Serializer? ser;
+      bool isDeclElemType =
+          (flags & IterableSerializer.isDeclElementTypeFlag) ==
+              IterableSerializer.isDeclElementTypeFlag;
+      if (isDeclElemType) {
+        ser = elemWrap?.ser;
+      }
+      if (ser == null) {
+        ser = pack.xtypeResolver.readTypeInfo(br).ser;
       }
-    }else {
-      Serializer? ser = elemWrap.ser;
-      if (ser == null){
+
+      if ((flags & IterableSerializer.trackingRefFlag) ==
+          IterableSerializer.trackingRefFlag) {
+        for (int i = 0; i < num; ++i) {
+          set.add(pack.foryDeser.xReadRefWithSer(br, ser, pack));
+        }
+      } else if ((flags & IterableSerializer.hasNullFlag) ==
+          IterableSerializer.hasNullFlag) {
         for (int i = 0; i < num; ++i) {
-          Object? o = pack.foryDeser.xReadRefNoSer(br, pack);
-          set.add(o);
+          if (br.readInt8() == RefFlag.NULL.id) {
+            set.add(null);
+          } else {
+            set.add(ser.read(br, -1, pack));
+          }
         }
-      }else{
+      } else {
         for (int i = 0; i < num; ++i) {
-          Object? o = pack.foryDeser.xReadRefWithSer(br, ser, pack);
-          set.add(o);
+          set.add(ser.read(br, -1, pack));
+        }
+      }
+    } else {
+      if ((flags & IterableSerializer.trackingRefFlag) ==
+          IterableSerializer.trackingRefFlag) {
+        for (int i = 0; i < num; ++i) {
+          set.add(pack.foryDeser.xReadRefNoSer(br, pack));
+        }
+      } else if ((flags & IterableSerializer.hasNullFlag) ==
+          IterableSerializer.hasNullFlag) {
+        for (int i = 0; i < num; ++i) {
+          if (br.readInt8() == RefFlag.NULL.id) {
+            set.add(null);
+          } else {
+            set.add(pack.foryDeser.xReadNonRefNoSer(br, pack));
+          }
+        }
+      } else {
+        for (int i = 0; i < num; ++i) {
+          set.add(pack.foryDeser.xReadNonRefNoSer(br, pack));
         }
       }
     }
-    if (elemWrap.hasGenericsParam){
+
+    if (hasGenericsParam) {
       pack.typeWrapStack.pop();
     }
     return set;
diff --git 
a/java/fory-core/src/test/java/org/apache/fory/xlang/DartXlangTest.java 
b/java/fory-core/src/test/java/org/apache/fory/xlang/DartXlangTest.java
new file mode 100644
index 000000000..26fd0d0c1
--- /dev/null
+++ b/java/fory-core/src/test/java/org/apache/fory/xlang/DartXlangTest.java
@@ -0,0 +1,294 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.fory.xlang;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import org.testng.SkipException;
+import org.testng.annotations.Test;
+
+/** Executes cross-language tests against the Dart implementation. */
+@Test
+public class DartXlangTest extends XlangTestBase {
+  private static final String DART_EXECUTABLE = "dart";
+  private static final String DART_MODULE =
+      "packages/fory-test/test/cross_lang_test/xlang_test_main.dart";
+
+  private static final List<String> DART_BASE_COMMAND =
+      Arrays.asList(DART_EXECUTABLE, "run", DART_MODULE, "<DART_TESTCASE>");
+
+  private static final int DART_TESTCASE_INDEX = 3;
+
+  @Override
+  protected void ensurePeerReady() {
+    String enabled = System.getenv("FORY_DART_JAVA_CI");
+    if (!"1".equals(enabled)) {
+      throw new SkipException("Skipping DartXlangTest: FORY_DART_JAVA_CI not 
set to 1");
+    }
+    boolean dartInstalled = true;
+    try {
+      Process process = new ProcessBuilder(DART_EXECUTABLE, 
"--version").start();
+      int exitCode = process.waitFor();
+      if (exitCode != 0) {
+        dartInstalled = false;
+      }
+    } catch (IOException | InterruptedException e) {
+      dartInstalled = false;
+      if (e instanceof InterruptedException) {
+        Thread.currentThread().interrupt();
+      }
+    }
+    if (!dartInstalled) {
+      throw new SkipException("Skipping DartXlangTest: dart not installed");
+    }
+  }
+
+  @Override
+  protected CommandContext buildCommandContext(String caseName, Path dataFile) 
{
+    List<String> command = new ArrayList<>(DART_BASE_COMMAND);
+    command.set(DART_TESTCASE_INDEX, caseName);
+    Map<String, String> env = envBuilder(dataFile);
+    env.put("ENABLE_FORY_DEBUG_OUTPUT", "1");
+    return new CommandContext(command, env, new File("../../dart"));
+  }
+
+  // 
============================================================================
+  // Test methods - duplicated from XlangTestBase for Maven Surefire discovery
+  // 
============================================================================
+
+  @Test
+  public void testBuffer() throws java.io.IOException {
+    super.testBuffer();
+  }
+
+  @Test
+  public void testBufferVar() throws java.io.IOException {
+    super.testBufferVar();
+  }
+
+  @Test
+  public void testMurmurHash3() throws java.io.IOException {
+    super.testMurmurHash3();
+  }
+
+  @Test
+  public void testStringSerializer() throws Exception {
+    super.testStringSerializer();
+  }
+
+  @Test
+  public void testCrossLanguageSerializer() throws Exception {
+    super.testCrossLanguageSerializer();
+  }
+
+  @Test(dataProvider = "enableCodegen")
+  public void testSimpleStruct(boolean enableCodegen) throws 
java.io.IOException {
+    super.testSimpleStruct(enableCodegen);
+  }
+
+  @Test
+  public void testSimpleNamedStructCodegenEnabled() throws java.io.IOException 
{
+    super.testSimpleNamedStruct(false);
+  }
+
+  @Test
+  public void testSimpleNamedStructCodegenDisabled() throws 
java.io.IOException {
+    super.testSimpleNamedStruct(false);
+  }
+
+  @Test(dataProvider = "enableCodegen")
+  public void testList(boolean enableCodegen) throws java.io.IOException {
+    super.testList(enableCodegen);
+  }
+
+  @Test(dataProvider = "enableCodegen")
+  public void testMap(boolean enableCodegen) throws java.io.IOException {
+    super.testMap(enableCodegen);
+  }
+
+  @Test(dataProvider = "enableCodegen")
+  public void testInteger(boolean enableCodegen) throws java.io.IOException {
+    super.testInteger(enableCodegen);
+  }
+
+  @Test(dataProvider = "enableCodegen")
+  public void testItem(boolean enableCodegen) throws java.io.IOException {
+    super.testItem(enableCodegen);
+  }
+
+  @Test(dataProvider = "enableCodegen")
+  public void testColor(boolean enableCodegen) throws java.io.IOException {
+    super.testColor(enableCodegen);
+  }
+
+  @Test(dataProvider = "enableCodegen")
+  public void testStructWithList(boolean enableCodegen) throws 
java.io.IOException {
+    super.testStructWithList(enableCodegen);
+  }
+
+  @Test(dataProvider = "enableCodegen")
+  public void testStructWithMap(boolean enableCodegen) throws 
java.io.IOException {
+    super.testStructWithMap(enableCodegen);
+  }
+
+  @Test(dataProvider = "enableCodegen")
+  public void testCollectionElementRefOverride(boolean enableCodegen) throws 
java.io.IOException {
+    super.testCollectionElementRefOverride(enableCodegen);
+  }
+
+  @Test(dataProvider = "enableCodegen")
+  public void testSkipIdCustom(boolean enableCodegen) throws 
java.io.IOException {
+    super.testSkipIdCustom(enableCodegen);
+  }
+
+  @Test(dataProvider = "enableCodegen")
+  public void testSkipNameCustom(boolean enableCodegen) throws 
java.io.IOException {
+    super.testSkipNameCustom(enableCodegen);
+  }
+
+  @Test(dataProvider = "enableCodegen")
+  public void testConsistentNamed(boolean enableCodegen) throws 
java.io.IOException {
+    super.testConsistentNamed(enableCodegen);
+  }
+
+  @Test(dataProvider = "enableCodegen")
+  public void testStructVersionCheck(boolean enableCodegen) throws 
java.io.IOException {
+    super.testStructVersionCheck(enableCodegen);
+  }
+
+  @Test(dataProvider = "enableCodegen")
+  public void testPolymorphicList(boolean enableCodegen) throws 
java.io.IOException {
+    super.testPolymorphicList(enableCodegen);
+  }
+
+  @Test(dataProvider = "enableCodegen")
+  public void testPolymorphicMap(boolean enableCodegen) throws 
java.io.IOException {
+    super.testPolymorphicMap(enableCodegen);
+  }
+
+  @Test(dataProvider = "enableCodegen")
+  public void testOneStringFieldSchemaConsistent(boolean enableCodegen) throws 
java.io.IOException {
+    super.testOneStringFieldSchemaConsistent(enableCodegen);
+  }
+
+  @Test(dataProvider = "enableCodegen")
+  public void testOneStringFieldCompatible(boolean enableCodegen) throws 
java.io.IOException {
+    super.testOneStringFieldCompatible(enableCodegen);
+  }
+
+  @Test(dataProvider = "enableCodegen")
+  public void testTwoStringFieldCompatible(boolean enableCodegen) throws 
java.io.IOException {
+    super.testTwoStringFieldCompatible(enableCodegen);
+  }
+
+  @Test(dataProvider = "enableCodegen")
+  public void testSchemaEvolutionCompatible(boolean enableCodegen) throws 
java.io.IOException {
+    super.testSchemaEvolutionCompatible(enableCodegen);
+  }
+
+  @Test(dataProvider = "enableCodegen")
+  public void testOneEnumFieldSchemaConsistent(boolean enableCodegen) throws 
java.io.IOException {
+    super.testOneEnumFieldSchemaConsistent(enableCodegen);
+  }
+
+  @Test(dataProvider = "enableCodegen")
+  public void testOneEnumFieldCompatible(boolean enableCodegen) throws 
java.io.IOException {
+    super.testOneEnumFieldCompatible(enableCodegen);
+  }
+
+  @Test(dataProvider = "enableCodegen")
+  public void testTwoEnumFieldCompatible(boolean enableCodegen) throws 
java.io.IOException {
+    super.testTwoEnumFieldCompatible(enableCodegen);
+  }
+
+  @Test(dataProvider = "enableCodegen")
+  public void testEnumSchemaEvolutionCompatible(boolean enableCodegen) throws 
java.io.IOException {
+    super.testEnumSchemaEvolutionCompatible(enableCodegen);
+  }
+
+  @Test(dataProvider = "enableCodegen")
+  public void testNullableFieldSchemaConsistentNotNull(boolean enableCodegen)
+      throws java.io.IOException {
+    super.testNullableFieldSchemaConsistentNotNull(enableCodegen);
+  }
+
+  @Test(dataProvider = "enableCodegen")
+  public void testNullableFieldSchemaConsistentNull(boolean enableCodegen)
+      throws java.io.IOException {
+    super.testNullableFieldSchemaConsistentNull(enableCodegen);
+  }
+
+  @Override
+  @Test(dataProvider = "enableCodegen")
+  public void testNullableFieldCompatibleNotNull(boolean enableCodegen) throws 
java.io.IOException {
+    super.testNullableFieldCompatibleNotNull(enableCodegen);
+  }
+
+  @Override
+  @Test(dataProvider = "enableCodegen")
+  public void testNullableFieldCompatibleNull(boolean enableCodegen) throws 
java.io.IOException {
+    super.testNullableFieldCompatibleNull(enableCodegen);
+  }
+
+  @Test(dataProvider = "enableCodegen")
+  public void testUnionXlang(boolean enableCodegen) throws java.io.IOException 
{
+    super.testUnionXlang(enableCodegen);
+  }
+
+  @Test(dataProvider = "enableCodegen")
+  public void testRefSchemaConsistent(boolean enableCodegen) throws 
java.io.IOException {
+    super.testRefSchemaConsistent(enableCodegen);
+  }
+
+  @Test(dataProvider = "enableCodegen")
+  public void testRefCompatible(boolean enableCodegen) throws 
java.io.IOException {
+    super.testRefCompatible(enableCodegen);
+  }
+
+  @Test(dataProvider = "enableCodegen")
+  public void testCircularRefSchemaConsistent(boolean enableCodegen) throws 
java.io.IOException {
+    super.testCircularRefSchemaConsistent(enableCodegen);
+  }
+
+  @Test(dataProvider = "enableCodegen")
+  public void testCircularRefCompatible(boolean enableCodegen) throws 
java.io.IOException {
+    super.testCircularRefCompatible(enableCodegen);
+  }
+
+  @Test(dataProvider = "enableCodegen")
+  public void testUnsignedSchemaConsistent(boolean enableCodegen) throws 
java.io.IOException {
+    super.testUnsignedSchemaConsistent(enableCodegen);
+  }
+
+  @Test(dataProvider = "enableCodegen")
+  public void testUnsignedSchemaConsistentSimple(boolean enableCodegen) throws 
java.io.IOException {
+    super.testUnsignedSchemaConsistentSimple(enableCodegen);
+  }
+
+  @Test(dataProvider = "enableCodegen")
+  public void testUnsignedSchemaCompatible(boolean enableCodegen) throws 
java.io.IOException {
+    super.testUnsignedSchemaCompatible(enableCodegen);
+  }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to