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 632e916b2 fix(xlang): fix xlang type system (#3646)
632e916b2 is described below

commit 632e916b2a8c790026acc96abc0c8acce9a2b8b2
Author: Shawn Yang <[email protected]>
AuthorDate: Mon May 4 22:16:10 2026 +0800

    fix(xlang): fix xlang type system (#3646)
    
    ## Why?
    
    
    
    ## What does this PR do?
    
    
    
    ## Related issues
    
    #3644
    
    ## AI Contribution Checklist
    
    
    
    - [ ] Substantial AI assistance was used in this PR: `yes` / `no`
    - [ ] If `yes`, I included a completed [AI Contribution
    
Checklist](https://github.com/apache/fory/blob/main/AI_POLICY.md#9-contributor-checklist-for-ai-assisted-prs)
    in this PR description and the required `AI Usage Disclosure`.
    - [ ] If `yes`, my PR description includes the required `ai_review`
    summary and screenshot evidence of the final clean AI review results
    from both fresh reviewers on the current PR diff or current HEAD after
    the latest code changes.
    
    
    
    ## Does this PR introduce any user-facing change?
    
    
    
    - [ ] Does this PR introduce any public API change?
    - [ ] Does this PR introduce any binary protocol compatibility change?
    
    ## Benchmark
---
 benchmarks/python/README.md                        |   2 +-
 compiler/fory_compiler/ir/validator.py             |  38 ++++-
 .../fory_compiler/tests/test_xlang_type_system.py  |  39 ++++-
 cpp/fory/serialization/temporal_serializers.h      |   4 +
 cpp/fory/serialization/union_serializer.h          |   2 +-
 dart/packages/fory/lib/src/fory.dart               |  22 +--
 .../scalar_and_typed_array_serializer_test.dart    |  15 ++
 docs/compiler/schema-idl.md                        |  10 +-
 docs/specification/xlang_serialization_spec.md     |   3 +-
 go/fory/field_spec.go                              |   2 -
 go/fory/tag_test.go                                |   8 --
 integration_tests/idl_tests/cpp/main.cc            | 159 ++++++++++++++++++---
 .../idl_tests/csharp/IdlTests/RoundtripTests.cs    |  95 +++++++++---
 .../idl_tests/dart/test/idl_roundtrip_test.dart    | 133 ++++++++++++++---
 .../idl_tests/go/idl_roundtrip_test.go             |  28 ++++
 integration_tests/idl_tests/idl/example.fdl        |  42 ++++++
 .../apache/fory/idl_tests/IdlRoundTripTest.java    | 114 ++++++++-------
 .../idl_tests/javascript/roundtrip.ts              |  36 ++++-
 .../idl_tests/javascript/test/roundtrip.test.ts    |  31 +++-
 .../idl_tests/python/idl_tests/roundtrip.py        |  25 ++++
 .../idl_tests/rust/tests/idl_roundtrip.rs          |  49 +++++--
 .../IdlRoundTripTests/IdlRoundTripTests.swift      |  44 +++++-
 .../serializer/kotlin/TypeUseAnnotationTest.kt     |  45 ++++++
 rust/fory/src/lib.rs                               |   2 +-
 .../serializer/scala/TypeUseAnnotationTest.scala   |  42 ++++++
 25 files changed, 807 insertions(+), 183 deletions(-)

diff --git a/benchmarks/python/README.md b/benchmarks/python/README.md
index 5a968f8fc..c2da3f807 100644
--- a/benchmarks/python/README.md
+++ b/benchmarks/python/README.md
@@ -7,7 +7,7 @@ This directory contains two benchmark entrypoints:
    - `StructList`, `SampleList`, `MediaContentList`
    - operations: `serialize`, `deserialize`
    - serializers: `fory`, `pickle`, `protobuf`
-2. `fory_benchmark.py`: CPython microbench script using the current 1.0 
annotation surface.
+2. `fory_benchmark.py`: CPython microbench script using the current annotation 
surface.
 
 ## Quick Start (Comprehensive Suite)
 
diff --git a/compiler/fory_compiler/ir/validator.py 
b/compiler/fory_compiler/ir/validator.py
index 439f65f35..eccd99ce8 100644
--- a/compiler/fory_compiler/ir/validator.py
+++ b/compiler/fory_compiler/ir/validator.py
@@ -37,6 +37,18 @@ from fory_compiler.ir.ast import (
 from fory_compiler.ir.types import ARRAY_ELEMENT_KINDS, PrimitiveKind
 from fory_compiler.ir.type_id import compute_registered_type_id
 
+INVALID_MAP_KEY_KINDS = {
+    PrimitiveKind.BYTES,
+    PrimitiveKind.FLOAT16,
+    PrimitiveKind.BFLOAT16,
+    PrimitiveKind.FLOAT32,
+    PrimitiveKind.FLOAT64,
+    PrimitiveKind.DECIMAL,
+}
+INVALID_MAP_KEY_MESSAGE = (
+    "map keys do not support binary, float, decimal, list, map, or array types"
+)
+
 
 @dataclass
 class ValidationIssue:
@@ -69,7 +81,7 @@ class SchemaValidator:
         self._check_messages()
         self._check_type_references()
         self._check_services()
-        self._check_array_rules()
+        self._check_collection_type_rules()
         if not self.allow_nested_collections:
             self._check_collection_nesting()
         self._check_ref_rules()
@@ -524,13 +536,17 @@ class SchemaValidator:
             for f in union.fields:
                 check_field(f, None)
 
-    def _check_array_rules(self) -> None:
+    def _check_collection_type_rules(self) -> None:
+        def invalid_map_key(field_type: FieldType) -> bool:
+            if isinstance(field_type, PrimitiveType):
+                return field_type.kind in INVALID_MAP_KEY_KINDS
+            return isinstance(field_type, (ListType, ArrayType, MapType))
+
         def check_type(field_type: FieldType, field: Field, in_map_key: bool = 
False):
             if isinstance(field_type, ArrayType):
                 if in_map_key:
-                    self._error(
-                        "array<T> is not valid as a map key type", 
field.location
-                    )
+                    self._error(INVALID_MAP_KEY_MESSAGE, field.location)
+                    return
                 element_type = field_type.element_type
                 if not isinstance(element_type, PrimitiveType):
                     self._error(
@@ -551,9 +567,19 @@ class SchemaValidator:
                     )
                 return
             if isinstance(field_type, ListType):
+                if in_map_key:
+                    self._error(INVALID_MAP_KEY_MESSAGE, field.location)
+                    return
                 check_type(field_type.element_type, field)
             elif isinstance(field_type, MapType):
-                check_type(field_type.key_type, field, in_map_key=True)
+                if in_map_key:
+                    self._error(INVALID_MAP_KEY_MESSAGE, field.location)
+                    return
+                key_type = field_type.key_type
+                if invalid_map_key(key_type):
+                    self._error(INVALID_MAP_KEY_MESSAGE, field.location)
+                else:
+                    check_type(key_type, field, in_map_key=True)
                 check_type(field_type.value_type, field)
 
         def check_message_fields(message: Message) -> None:
diff --git a/compiler/fory_compiler/tests/test_xlang_type_system.py 
b/compiler/fory_compiler/tests/test_xlang_type_system.py
index 49a4be789..b03be3699 100644
--- a/compiler/fory_compiler/tests/test_xlang_type_system.py
+++ b/compiler/fory_compiler/tests/test_xlang_type_system.py
@@ -108,12 +108,24 @@ def test_array_type_is_distinct_from_list_type():
         "any",
         "date",
         "timestamp",
+        "duration",
         "decimal",
+        "ExampleState",
         "Child",
+        "ChildUnion",
     ],
 )
 def test_array_rejects_non_fixed_width_number_and_bool_elements(element):
     source = f"""
+    enum ExampleState {{
+        UNKNOWN = 0;
+        READY = 1;
+    }}
+
+    union ChildUnion {{
+        string note = 1;
+    }}
+
     message Child {{
         string name = 1;
     }}
@@ -151,18 +163,33 @@ def 
test_array_rejects_optional_or_ref_elements_at_parse_time():
         )
 
 
-def test_array_is_not_valid_as_map_key():
[email protected](
+    "key_type",
+    [
+        "bytes",
+        "float16",
+        "bfloat16",
+        "float32",
+        "float64",
+        "decimal",
+        "list<int32>",
+        "array<uint8>",
+        "map<string, int32>",
+    ],
+)
+def test_map_rejects_non_portable_key_types(key_type):
     _schema, validator, ok = validate_schema(
-        """
-        message InvalidMap {
-            map<array<uint8>, string> values = 1;
-        }
+        f"""
+        message InvalidMap {{
+            map<{key_type}, string> values = 1;
+        }}
         """
     )
 
     assert not ok
     assert any(
-        "array<T> is not valid as a map key type" in err.message
+        "map keys do not support binary, float, decimal, list, map, or array 
types"
+        in err.message
         for err in validator.errors
     )
 
diff --git a/cpp/fory/serialization/temporal_serializers.h 
b/cpp/fory/serialization/temporal_serializers.h
index 86737059e..978809c6b 100644
--- a/cpp/fory/serialization/temporal_serializers.h
+++ b/cpp/fory/serialization/temporal_serializers.h
@@ -51,6 +51,10 @@ public:
 
   bool operator!=(const Date &other) const { return !(*this == other); }
 
+  bool operator<(const Date &other) const {
+    return days_since_epoch_ < other.days_since_epoch_;
+  }
+
 private:
   int32_t days_since_epoch_; // Days since Jan 1, 1970 UTC
 };
diff --git a/cpp/fory/serialization/union_serializer.h 
b/cpp/fory/serialization/union_serializer.h
index 2367fde88..2fda11fac 100644
--- a/cpp/fory/serialization/union_serializer.h
+++ b/cpp/fory/serialization/union_serializer.h
@@ -40,7 +40,7 @@
 namespace fory {
 namespace serialization {
 
-// Union metadata specializations generated by compiler (legacy).
+// Compiler-generated union metadata specializations.
 template <typename T, typename Enable = void> struct UnionCaseIds;
 template <typename T, uint32_t CaseId> struct UnionCaseMeta;
 
diff --git a/dart/packages/fory/lib/src/fory.dart 
b/dart/packages/fory/lib/src/fory.dart
index f082a4eab..80d819048 100644
--- a/dart/packages/fory/lib/src/fory.dart
+++ b/dart/packages/fory/lib/src/fory.dart
@@ -43,7 +43,8 @@ final class Fory {
   static const int _xlangHeaderFlag = 0x02;
   static const int _outOfBandHeaderFlag = 0x04;
 
-  late final Buffer _buffer;
+  late final Buffer _readBuffer;
+  late final Buffer _writeBuffer;
   late final WriteContext _writeContext;
   late final ReadContext _readContext;
   late final TypeResolver _typeResolver;
@@ -66,7 +67,8 @@ final class Fory {
       maxCollectionSize: maxCollectionSize,
       maxBinarySize: maxBinarySize,
     );
-    _buffer = Buffer();
+    _readBuffer = Buffer();
+    _writeBuffer = Buffer();
     _typeResolver = TypeResolver(config);
     _writeContext = WriteContext(
       config,
@@ -88,9 +90,9 @@ final class Fory {
   /// that needs shared-reference tracking and there is no field metadata to
   /// request it. Annotated fields should still use `@ForyField(ref: true)`.
   Uint8List serialize(Object? value, {bool trackRef = false}) {
-    _buffer.clear();
-    serializeTo(value, _buffer, trackRef: trackRef);
-    return Uint8List.fromList(_buffer.toBytes());
+    _writeBuffer.clear();
+    serializeTo(value, _writeBuffer, trackRef: trackRef);
+    return Uint8List.fromList(_writeBuffer.toBytes());
   }
 
   /// Serializes a non-null builtin [value] using the explicit xlang
@@ -104,14 +106,14 @@ final class Fory {
     required int wireTypeId,
     bool trackRef = false,
   }) {
-    _buffer.clear();
+    _writeBuffer.clear();
     serializeBuiltinTo(
       value,
-      _buffer,
+      _writeBuffer,
       wireTypeId: wireTypeId,
       trackRef: trackRef,
     );
-    return Uint8List.fromList(_buffer.toBytes());
+    return Uint8List.fromList(_writeBuffer.toBytes());
   }
 
   /// Serializes [value] into [buffer].
@@ -163,8 +165,8 @@ final class Fory {
   /// The payload is decoded from its wire metadata first. `T` is used as a
   /// post-read type check, not as an alternate schema.
   T deserialize<T>(Uint8List bytes) {
-    _buffer.wrap(bytes);
-    return deserializeFrom<T>(_buffer);
+    _readBuffer.wrap(bytes);
+    return deserializeFrom<T>(_readBuffer);
   }
 
   /// Deserializes a value from [buffer] and checks that it is assignable to
diff --git 
a/dart/packages/fory/test/scalar_and_typed_array_serializer_test.dart 
b/dart/packages/fory/test/scalar_and_typed_array_serializer_test.dart
index c58b902a1..5d61240ab 100644
--- a/dart/packages/fory/test/scalar_and_typed_array_serializer_test.dart
+++ b/dart/packages/fory/test/scalar_and_typed_array_serializer_test.dart
@@ -389,6 +389,21 @@ void main() {
       );
     });
 
+    test('reuses Fory after typed-array reads without corrupting views', () {
+      final fory = Fory();
+      final values = <Int32List>[
+        Int32List.fromList(<int>[1, 2]),
+        Int32List.fromList(<int>[3, 4]),
+      ];
+
+      final decoded = fory.deserialize<List<Object?>>(fory.serialize(values));
+      final encodedAgain = fory.serialize(decoded);
+      final roundTrip = fory.deserialize<List<Object?>>(encodedAgain);
+
+      expect((roundTrip[0] as Int32List).toList(), orderedEquals(<int>[1, 2]));
+      expect((roundTrip[1] as Int32List).toList(), orderedEquals(<int>[3, 4]));
+    });
+
     test('round-trips empty binary and typed array payloads', () {
       final fory = Fory();
 
diff --git a/docs/compiler/schema-idl.md b/docs/compiler/schema-idl.md
index 68bcf70d8..63a6e3ef3 100644
--- a/docs/compiler/schema-idl.md
+++ b/docs/compiler/schema-idl.md
@@ -1274,7 +1274,7 @@ Generated carriers are language-specific, but the schema 
kind is not:
 | ----------------- | ---------------------------- | ---------------------- | 
-------------- | ------------------------ |
 | `list<bool>`      | `BoolList` / `List<Boolean>` | `List[bool]`           | 
`List<bool>`   | `Type.list(Type.bool())` |
 | `array<bool>`     | `boolean[]`                  | `pyfory.BoolArray`     | 
`BoolList`     | `Type.boolArray()`       |
-| `array<int8>`     | `byte[]`                     | `pyfory.Int8Array`     | 
`Int8List`     | `Type.int8Array()`       |
+| `array<int8>`     | `@Int8Type byte[]`           | `pyfory.Int8Array`     | 
`Int8List`     | `Type.int8Array()`       |
 | `array<int16>`    | `short[]`                    | `pyfory.Int16Array`    | 
`Int16List`    | `Type.int16Array()`      |
 | `array<int32>`    | `int[]`                      | `pyfory.Int32Array`    | 
`Int32List`    | `Type.int32Array()`      |
 | `array<int64>`    | `long[]`                     | `pyfory.Int64Array`    | 
`Int64List`    | `Type.int64Array()`      |
@@ -1316,10 +1316,14 @@ message Config {
 **Key Type Restrictions:**
 
 - `string` (most common)
-- Integer types (`int8`, `int16`, `int32`, `int64`)
 - `bool`
+- Integer types (`int8`, `int16`, `int32`, `int64`, `uint8`, `uint16`, 
`uint32`, `uint64`)
+- Temporal scalar types (`date`, `timestamp`, `duration`)
+- Enums
 
-Avoid using messages or complex types as keys.
+Map keys do not support binary `bytes`, floating-point types, `decimal`, 
`list<T>`, `array<T>`,
+or nested `map<K, V>` types. Put those types in map values or wrap them in a 
message with a
+portable scalar or enum key.
 
 ### Type Compatibility Matrix
 
diff --git a/docs/specification/xlang_serialization_spec.md 
b/docs/specification/xlang_serialization_spec.md
index 37a196801..24adbe333 100644
--- a/docs/specification/xlang_serialization_spec.md
+++ b/docs/specification/xlang_serialization_spec.md
@@ -63,7 +63,8 @@ This specification defines the Fory xlang binary format. The 
format is dynamic r
 - named_ext: an `ext` type whose type mapping will be encoded as a name.
 - list: a sequence of objects.
 - set: an unordered set of unique elements.
-- map: a map of key-value pairs. Mutable types such as `list/map/set/array` 
are not allowed as key of map.
+- map: a map of key-value pairs. Map keys do not allow binary values, 
floating-point values,
+  decimal values, or collection-shaped values such as `list`, `map`, `set`, 
and `array`.
 - duration: an absolute length of time, independent of any calendar/timezone, 
as a count of nanoseconds.
 - timestamp: a point in time, independent of any calendar/timezone, encoded as 
seconds (int64) and nanoseconds
   (uint32) since the epoch at UTC midnight on January 1, 1970.
diff --git a/go/fory/field_spec.go b/go/fory/field_spec.go
index cd7e59b20..68f15a69b 100644
--- a/go/fory/field_spec.go
+++ b/go/fory/field_spec.go
@@ -558,8 +558,6 @@ func parseFieldTag(field reflect.StructField) 
(parsedFieldTag, error) {
                        }
                        parsed.typeHintSet = true
                        parsed.typeHint = hint
-               case "compress", "nested_ref":
-                       return parsedFieldTag{}, InvalidTagErrorf("unsupported 
legacy fory tag key %q on field %s", key, field.Name)
                default:
                        return parsedFieldTag{}, InvalidTagErrorf("unknown fory 
tag key %q on field %s", key, field.Name)
                }
diff --git a/go/fory/tag_test.go b/go/fory/tag_test.go
index aeeb551dd..11382d6f7 100644
--- a/go/fory/tag_test.go
+++ b/go/fory/tag_test.go
@@ -220,12 +220,6 @@ func TestParseFieldSpecRejectsInvalidTags(t *testing.T) {
        type UnknownKey struct {
                Value int32 `fory:"id=0,unknown=true"`
        }
-       type LegacyCompress struct {
-               Value uint32 `fory:"compress=true"`
-       }
-       type LegacyNestedRef struct {
-               Value []int32 `fory:"nested_ref=[[]]"`
-       }
        type BadDSL struct {
                Value []int32 `fory:"type=list(element=int32(encoding=fixed)"`
        }
@@ -254,8 +248,6 @@ func TestParseFieldSpecRejectsInvalidTags(t *testing.T) {
        }{
                {name: "duplicate keys", typ: reflect.TypeOf(DuplicateKeys{})},
                {name: "unknown key", typ: reflect.TypeOf(UnknownKey{})},
-               {name: "legacy compress", typ: 
reflect.TypeOf(LegacyCompress{})},
-               {name: "legacy nested_ref", typ: 
reflect.TypeOf(LegacyNestedRef{})},
                {name: "bad dsl", typ: reflect.TypeOf(BadDSL{})},
                {name: "impossible override", typ: 
reflect.TypeOf(ImpossibleOverride{})},
                {name: "encoding conflict", typ: reflect.TypeOf(Conflict{})},
diff --git a/integration_tests/idl_tests/cpp/main.cc 
b/integration_tests/idl_tests/cpp/main.cc
index b97bd857d..8e41bd1d5 100644
--- a/integration_tests/idl_tests/cpp/main.cc
+++ b/integration_tests/idl_tests/cpp/main.cc
@@ -433,7 +433,7 @@ struct ExampleMessageLists {
                fory::F(132).list(fory::T::inner(fory::T::uint64().varint()))));
 };
 
-struct ExampleMessageArraysMaps {
+struct ExampleMessageArrays {
   std::vector<bool> bool_array;
   std::vector<int8_t> int8_array;
   std::vector<int16_t> int16_array;
@@ -449,6 +449,28 @@ struct ExampleMessageArraysMaps {
   std::vector<double> float64_array;
   std::vector<std::vector<int32_t>> int32_array_list;
   std::vector<std::vector<uint8_t>> uint8_array_list;
+
+  FORY_STRUCT(ExampleMessageArrays,
+              (bool_array, fory::F(301).array(fory::T::boolean())),
+              (int8_array, fory::F(302).array(fory::T::int8())),
+              (int16_array, fory::F(303).array(fory::T::int16())),
+              (int32_array, fory::F(304).array(fory::T::int32())),
+              (int64_array, fory::F(305).array(fory::T::int64())),
+              (uint8_array, fory::F(306).array(fory::T::uint8())),
+              (uint16_array, fory::F(307).array(fory::T::uint16())),
+              (uint32_array, fory::F(308).array(fory::T::uint32())),
+              (uint64_array, fory::F(309).array(fory::T::uint64())),
+              (float16_array, fory::F(310).array(fory::T::float16())),
+              (bfloat16_array, fory::F(311).array(fory::T::bfloat16())),
+              (float32_array, fory::F(312).array(fory::T::float32())),
+              (float64_array, fory::F(313).array(fory::T::float64())),
+              (int32_array_list,
+               fory::F(314).list(fory::T::array(fory::T::int32()))),
+              (uint8_array_list,
+               fory::F(315).list(fory::T::array(fory::T::uint8()))));
+};
+
+struct ExampleMessageMaps {
   std::map<bool, std::string> string_values_by_bool;
   std::map<int8_t, std::string> string_values_by_int8;
   std::map<int16_t, std::string> string_values_by_int16;
@@ -482,24 +504,31 @@ struct ExampleMessageArraysMaps {
   std::map<std::string, std::vector<uint8_t>> uint8_array_values_by_name;
   std::map<std::string, std::vector<float>> float32_array_values_by_name;
   std::map<std::string, std::vector<int32_t>> int32_array_values_by_name;
+  std::map<fory::serialization::Date, std::string> string_values_by_date;
+  std::map<std::string, bool> bool_values_by_name;
+  std::map<std::string, int8_t> int8_values_by_name;
+  std::map<std::string, int16_t> int16_values_by_name;
+  std::map<std::string, int32_t> fixed_i32_values_by_name;
+  std::map<std::string, int32_t> varint_i32_values_by_name;
+  std::map<std::string, int64_t> fixed_i64_values_by_name;
+  std::map<std::string, int64_t> varint_i64_values_by_name;
+  std::map<std::string, int64_t> tagged_i64_values_by_name;
+  std::map<std::string, uint8_t> uint8_values_by_name;
+  std::map<std::string, uint16_t> uint16_values_by_name;
+  std::map<std::string, uint32_t> fixed_u32_values_by_name;
+  std::map<std::string, uint32_t> varint_u32_values_by_name;
+  std::map<std::string, uint64_t> fixed_u64_values_by_name;
+  std::map<std::string, uint64_t> varint_u64_values_by_name;
+  std::map<std::string, uint64_t> tagged_u64_values_by_name;
+  std::map<std::string, float> float32_values_by_name;
+  std::map<std::string, double> float64_values_by_name;
+  std::map<std::string, fory::serialization::Timestamp>
+      timestamp_values_by_name;
+  std::map<std::string, fory::serialization::Duration> duration_values_by_name;
+  std::map<std::string, ExampleState> enum_values_by_name;
 
   FORY_STRUCT(
-      ExampleMessageArraysMaps,
-      (bool_array, fory::F(301).array(fory::T::boolean())),
-      (int8_array, fory::F(302).array(fory::T::int8())),
-      (int16_array, fory::F(303).array(fory::T::int16())),
-      (int32_array, fory::F(304).array(fory::T::int32())),
-      (int64_array, fory::F(305).array(fory::T::int64())),
-      (uint8_array, fory::F(306).array(fory::T::uint8())),
-      (uint16_array, fory::F(307).array(fory::T::uint16())),
-      (uint32_array, fory::F(308).array(fory::T::uint32())),
-      (uint64_array, fory::F(309).array(fory::T::uint64())),
-      (float16_array, fory::F(310).array(fory::T::float16())),
-      (bfloat16_array, fory::F(311).array(fory::T::bfloat16())),
-      (float32_array, fory::F(312).array(fory::T::float32())),
-      (float64_array, fory::F(313).array(fory::T::float64())),
-      (int32_array_list, fory::F(314).list(fory::T::array(fory::T::int32()))),
-      (uint8_array_list, fory::F(315).list(fory::T::array(fory::T::uint8()))),
+      ExampleMessageMaps,
       (string_values_by_bool,
        fory::F(201).map(fory::T::boolean(), fory::T::string())),
       (string_values_by_int8,
@@ -562,12 +591,55 @@ struct ExampleMessageArraysMaps {
       (float32_array_values_by_name,
        fory::F(232).map(fory::T::string(), 
fory::T::array(fory::T::float32()))),
       (int32_array_values_by_name,
-       fory::F(233).map(fory::T::string(), fory::T::array(fory::T::int32()))));
+       fory::F(233).map(fory::T::string(), fory::T::array(fory::T::int32()))),
+      (string_values_by_date,
+       fory::F(234).map(fory::FieldNodeSpec{}, fory::T::string())),
+      (bool_values_by_name,
+       fory::F(236).map(fory::T::string(), fory::T::boolean())),
+      (int8_values_by_name,
+       fory::F(237).map(fory::T::string(), fory::T::int8())),
+      (int16_values_by_name,
+       fory::F(238).map(fory::T::string(), fory::T::int16())),
+      (fixed_i32_values_by_name,
+       fory::F(239).map(fory::T::string(), fory::T::int32().fixed())),
+      (varint_i32_values_by_name,
+       fory::F(240).map(fory::T::string(), fory::T::int32().varint())),
+      (fixed_i64_values_by_name,
+       fory::F(241).map(fory::T::string(), fory::T::int64().fixed())),
+      (varint_i64_values_by_name,
+       fory::F(242).map(fory::T::string(), fory::T::int64().varint())),
+      (tagged_i64_values_by_name,
+       fory::F(243).map(fory::T::string(), fory::T::int64().tagged())),
+      (uint8_values_by_name,
+       fory::F(244).map(fory::T::string(), fory::T::uint8())),
+      (uint16_values_by_name,
+       fory::F(245).map(fory::T::string(), fory::T::uint16())),
+      (fixed_u32_values_by_name,
+       fory::F(246).map(fory::T::string(), fory::T::uint32().fixed())),
+      (varint_u32_values_by_name,
+       fory::F(247).map(fory::T::string(), fory::T::uint32().varint())),
+      (fixed_u64_values_by_name,
+       fory::F(248).map(fory::T::string(), fory::T::uint64().fixed())),
+      (varint_u64_values_by_name,
+       fory::F(249).map(fory::T::string(), fory::T::uint64().varint())),
+      (tagged_u64_values_by_name,
+       fory::F(250).map(fory::T::string(), fory::T::uint64().tagged())),
+      (float32_values_by_name,
+       fory::F(251).map(fory::T::string(), fory::T::float32())),
+      (float64_values_by_name,
+       fory::F(252).map(fory::T::string(), fory::T::float64())),
+      (timestamp_values_by_name,
+       fory::F(253).map(fory::T::string(), fory::FieldNodeSpec{})),
+      (duration_values_by_name,
+       fory::F(254).map(fory::T::string(), fory::FieldNodeSpec{})),
+      (enum_values_by_name,
+       fory::F(255).map(fory::T::string(), fory::FieldNodeSpec{})));
 };
 
 struct ExampleMessage : ExampleMessageScalars,
                         ExampleMessageLists,
-                        ExampleMessageArraysMaps {
+                        ExampleMessageArrays,
+                        ExampleMessageMaps {
 
   bool operator==(const ExampleMessage &other) const {
     return std::tie(
@@ -605,7 +677,17 @@ struct ExampleMessage : ExampleMessageScalars,
                date_values_by_name, decimal_values_by_name,
                message_values_by_name, union_values_by_name,
                uint8_array_values_by_name, float32_array_values_by_name,
-               int32_array_values_by_name) ==
+               int32_array_values_by_name, string_values_by_date,
+               bool_values_by_name, int8_values_by_name, int16_values_by_name,
+               fixed_i32_values_by_name, varint_i32_values_by_name,
+               fixed_i64_values_by_name, varint_i64_values_by_name,
+               tagged_i64_values_by_name, uint8_values_by_name,
+               uint16_values_by_name, fixed_u32_values_by_name,
+               varint_u32_values_by_name, fixed_u64_values_by_name,
+               varint_u64_values_by_name, tagged_u64_values_by_name,
+               float32_values_by_name, float64_values_by_name,
+               timestamp_values_by_name, duration_values_by_name,
+               enum_values_by_name) ==
            std::tie(
                other.bool_value, other.int8_value, other.int16_value,
                other.fixed_i32_value, other.varint_i32_value,
@@ -656,12 +738,22 @@ struct ExampleMessage : ExampleMessageScalars,
                other.message_values_by_name, other.union_values_by_name,
                other.uint8_array_values_by_name,
                other.float32_array_values_by_name,
-               other.int32_array_values_by_name);
+               other.int32_array_values_by_name, other.string_values_by_date,
+               other.bool_values_by_name, other.int8_values_by_name,
+               other.int16_values_by_name, other.fixed_i32_values_by_name,
+               other.varint_i32_values_by_name, other.fixed_i64_values_by_name,
+               other.varint_i64_values_by_name, 
other.tagged_i64_values_by_name,
+               other.uint8_values_by_name, other.uint16_values_by_name,
+               other.fixed_u32_values_by_name, other.varint_u32_values_by_name,
+               other.fixed_u64_values_by_name, other.varint_u64_values_by_name,
+               other.tagged_u64_values_by_name, other.float32_values_by_name,
+               other.float64_values_by_name, other.timestamp_values_by_name,
+               other.duration_values_by_name, other.enum_values_by_name);
   }
 
   FORY_STRUCT(ExampleMessage, FORY_BASE(ExampleMessageScalars),
-              FORY_BASE(ExampleMessageLists),
-              FORY_BASE(ExampleMessageArraysMaps));
+              FORY_BASE(ExampleMessageLists), FORY_BASE(ExampleMessageArrays),
+              FORY_BASE(ExampleMessageMaps));
 };
 
 FORY_ENUM(ExampleState, UNKNOWN, READY, FAILED);
@@ -835,6 +927,27 @@ example_peer::ExampleMessage BuildExampleMessage() {
       {"u8", {static_cast<uint8_t>(201), static_cast<uint8_t>(202)}}};
   message.float32_array_values_by_name = {{"f32", {1.25F, 2.5F}}};
   message.int32_array_values_by_name = {{"i32", {101, 202}}};
+  message.string_values_by_date = {{Date(19850), "date-key"}};
+  message.bool_values_by_name = {{"bool", true}};
+  message.int8_values_by_name = {{"int8", -8}};
+  message.int16_values_by_name = {{"int16", -16}};
+  message.fixed_i32_values_by_name = {{"fixed-i32", -32}};
+  message.varint_i32_values_by_name = {{"varint-i32", 32}};
+  message.fixed_i64_values_by_name = {{"fixed-i64", -64}};
+  message.varint_i64_values_by_name = {{"varint-i64", 64}};
+  message.tagged_i64_values_by_name = {{"tagged-i64", 65}};
+  message.uint8_values_by_name = {{"uint8", static_cast<uint8_t>(208)}};
+  message.uint16_values_by_name = {{"uint16", 60001}};
+  message.fixed_u32_values_by_name = {{"fixed-u32", 1234567892U}};
+  message.varint_u32_values_by_name = {{"varint-u32", 1234567893U}};
+  message.fixed_u64_values_by_name = {{"fixed-u64", 9876543213ULL}};
+  message.varint_u64_values_by_name = {{"varint-u64", 9876543214ULL}};
+  message.tagged_u64_values_by_name = {{"tagged-u64", 9876543215ULL}};
+  message.float32_values_by_name = {{"float32", 3.25F}};
+  message.float64_values_by_name = {{"float64", 6.5}};
+  message.timestamp_values_by_name = {{"timestamp", ts(1717747750)}};
+  message.duration_values_by_name = {{"duration", std::chrono::seconds(10)}};
+  message.enum_values_by_name = {{"enum", example_peer::ExampleState::FAILED}};
   return message;
 }
 
diff --git a/integration_tests/idl_tests/csharp/IdlTests/RoundtripTests.cs 
b/integration_tests/idl_tests/csharp/IdlTests/RoundtripTests.cs
index 4dbc99c88..92b5bb089 100644
--- a/integration_tests/idl_tests/csharp/IdlTests/RoundtripTests.cs
+++ b/integration_tests/idl_tests/csharp/IdlTests/RoundtripTests.cs
@@ -695,6 +695,36 @@ public sealed class RoundtripTests
             {
                 ["i32"] = [101, 202],
             },
+            StringValuesByDate = new Dictionary<DateOnly, string>
+            {
+                [new DateOnly(2024, 5, 7)] = "date-key",
+            },
+            BoolValuesByName = new Dictionary<string, bool> { ["bool"] = true 
},
+            Int8ValuesByName = new Dictionary<string, sbyte> { ["int8"] = -8 },
+            Int16ValuesByName = new Dictionary<string, short> { ["int16"] = 
-16 },
+            FixedI32ValuesByName = new Dictionary<string, int> { ["fixed-i32"] 
= -32 },
+            VarintI32ValuesByName = new Dictionary<string, int> { 
["varint-i32"] = 32 },
+            FixedI64ValuesByName = new Dictionary<string, long> { 
["fixed-i64"] = -64 },
+            VarintI64ValuesByName = new Dictionary<string, long> { 
["varint-i64"] = 64 },
+            TaggedI64ValuesByName = new Dictionary<string, long> { 
["tagged-i64"] = 65 },
+            Uint8ValuesByName = new Dictionary<string, byte> { ["uint8"] = 208 
},
+            Uint16ValuesByName = new Dictionary<string, ushort> { ["uint16"] = 
60001 },
+            FixedU32ValuesByName = new Dictionary<string, uint> { 
["fixed-u32"] = 1234567892 },
+            VarintU32ValuesByName = new Dictionary<string, uint> { 
["varint-u32"] = 1234567893 },
+            FixedU64ValuesByName = new Dictionary<string, ulong> { 
["fixed-u64"] = 9876543213 },
+            VarintU64ValuesByName = new Dictionary<string, ulong> { 
["varint-u64"] = 9876543214 },
+            TaggedU64ValuesByName = new Dictionary<string, ulong> { 
["tagged-u64"] = 9876543215 },
+            Float32ValuesByName = new Dictionary<string, float> { ["float32"] 
= 3.25f },
+            Float64ValuesByName = new Dictionary<string, double> { ["float64"] 
= 6.5 },
+            TimestampValuesByName = new Dictionary<string, DateTimeOffset>
+            {
+                ["timestamp"] = DateTimeOffset.Parse(
+                    "2024-06-07T08:09:10Z",
+                    CultureInfo.InvariantCulture,
+                    DateTimeStyles.AssumeUniversal | 
DateTimeStyles.AdjustToUniversal),
+            },
+            DurationValuesByName = new Dictionary<string, TimeSpan> { 
["duration"] = TimeSpan.FromSeconds(10) },
+            EnumValuesByName = new Dictionary<string, example.ExampleState> { 
["enum"] = example.ExampleState.Failed },
         };
     }
 
@@ -1106,6 +1136,27 @@ public sealed class RoundtripTests
         AssertArrayMap(expected.Uint8ArrayValuesByName, 
actual.Uint8ArrayValuesByName);
         AssertArrayMap(expected.Float32ArrayValuesByName, 
actual.Float32ArrayValuesByName);
         AssertArrayMap(expected.Int32ArrayValuesByName, 
actual.Int32ArrayValuesByName);
+        AssertMap(expected.StringValuesByDate, actual.StringValuesByDate);
+        AssertMap(expected.BoolValuesByName, actual.BoolValuesByName);
+        AssertMap(expected.Int8ValuesByName, actual.Int8ValuesByName);
+        AssertMap(expected.Int16ValuesByName, actual.Int16ValuesByName);
+        AssertMap(expected.FixedI32ValuesByName, actual.FixedI32ValuesByName);
+        AssertMap(expected.VarintI32ValuesByName, 
actual.VarintI32ValuesByName);
+        AssertMap(expected.FixedI64ValuesByName, actual.FixedI64ValuesByName);
+        AssertMap(expected.VarintI64ValuesByName, 
actual.VarintI64ValuesByName);
+        AssertMap(expected.TaggedI64ValuesByName, 
actual.TaggedI64ValuesByName);
+        AssertMap(expected.Uint8ValuesByName, actual.Uint8ValuesByName);
+        AssertMap(expected.Uint16ValuesByName, actual.Uint16ValuesByName);
+        AssertMap(expected.FixedU32ValuesByName, actual.FixedU32ValuesByName);
+        AssertMap(expected.VarintU32ValuesByName, 
actual.VarintU32ValuesByName);
+        AssertMap(expected.FixedU64ValuesByName, actual.FixedU64ValuesByName);
+        AssertMap(expected.VarintU64ValuesByName, 
actual.VarintU64ValuesByName);
+        AssertMap(expected.TaggedU64ValuesByName, 
actual.TaggedU64ValuesByName);
+        AssertMap(expected.Float32ValuesByName, actual.Float32ValuesByName);
+        AssertMap(expected.Float64ValuesByName, actual.Float64ValuesByName);
+        AssertMap(expected.TimestampValuesByName, 
actual.TimestampValuesByName);
+        AssertMap(expected.DurationValuesByName, actual.DurationValuesByName);
+        AssertMap(expected.EnumValuesByName, actual.EnumValuesByName);
     }
 
     private static void AssertExampleLeaf(example.ExampleLeaf? expected, 
example.ExampleLeaf? actual)
@@ -1491,22 +1542,22 @@ public sealed class RoundtripTests
                 result = [.. strEnumerable];
                 return true;
             case IEnumerable<object?> objEnumerable:
-            {
-                List<string> normalized = [];
-                foreach (object? item in objEnumerable)
                 {
-                    if (item is not string text)
+                    List<string> normalized = [];
+                    foreach (object? item in objEnumerable)
                     {
-                        result = [];
-                        return false;
+                        if (item is not string text)
+                        {
+                            result = [];
+                            return false;
+                        }
+
+                        normalized.Add(text);
                     }
 
-                    normalized.Add(text);
+                    result = normalized;
+                    return true;
                 }
-
-                result = normalized;
-                return true;
-            }
             default:
                 result = [];
                 return false;
@@ -1524,22 +1575,22 @@ public sealed class RoundtripTests
                 result = readonlyMap.ToDictionary(kv => kv.Key, kv => 
kv.Value);
                 return true;
             case IEnumerable<KeyValuePair<object, object?>> objectPairs:
-            {
-                Dictionary<string, string> normalized = [];
-                foreach (KeyValuePair<object, object?> pair in objectPairs)
                 {
-                    if (pair.Key is not string key || pair.Value is not string 
val)
+                    Dictionary<string, string> normalized = [];
+                    foreach (KeyValuePair<object, object?> pair in objectPairs)
                     {
-                        result = [];
-                        return false;
+                        if (pair.Key is not string key || pair.Value is not 
string val)
+                        {
+                            result = [];
+                            return false;
+                        }
+
+                        normalized[key] = val;
                     }
 
-                    normalized[key] = val;
+                    result = normalized;
+                    return true;
                 }
-
-                result = normalized;
-                return true;
-            }
             default:
                 result = [];
                 return false;
diff --git a/integration_tests/idl_tests/dart/test/idl_roundtrip_test.dart 
b/integration_tests/idl_tests/dart/test/idl_roundtrip_test.dart
index e4d97cea7..c58660362 100644
--- a/integration_tests/idl_tests/dart/test/idl_roundtrip_test.dart
+++ b/integration_tests/idl_tests/dart/test/idl_roundtrip_test.dart
@@ -373,8 +373,10 @@ example.ExampleMessage buildExampleMessage() {
     ..uint32Array = Uint32List.fromList(<int>[2000000000, 2100000000])
     ..uint64Array = Uint64List.fromList(<int>[9000000000, 12000000000])
     ..float16Array = Float16List.fromList(<Float16>[Float16(1.0), 
Float16(2.0)])
-    ..bfloat16Array =
-        Bfloat16List.fromList(<Bfloat16>[Bfloat16(1.0), Bfloat16(2.0)])
+    ..bfloat16Array = Bfloat16List.fromList(<Bfloat16>[
+      Bfloat16(1.0),
+      Bfloat16(2.0),
+    ])
     ..float32Array = Float32List.fromList(<double>[1.5, 2.5])
     ..float64Array = Float64List.fromList(<double>[3.5, 4.5])
     ..int32ArrayList = <Int32List>[
@@ -399,10 +401,10 @@ example.ExampleMessage buildExampleMessage() {
     ..stringValuesByVarintU32 = <int, String>{1234567891: 'varint-u32'}
     ..stringValuesByFixedU64 = <Uint64, String>{Uint64(9876543210): 
'fixed-u64'}
     ..stringValuesByVarintU64 = <Uint64, String>{
-      Uint64(9876543211): 'varint-u64'
+      Uint64(9876543211): 'varint-u64',
     }
     ..stringValuesByTaggedU64 = <Uint64, String>{
-      Uint64(9876543212): 'tagged-u64'
+      Uint64(9876543212): 'tagged-u64',
     }
     ..stringValuesByString = <String, String>{'name': 'value'}
     ..stringValuesByTimestamp = <Timestamp, String>{
@@ -441,6 +443,35 @@ example.ExampleMessage buildExampleMessage() {
     }
     ..int32ArrayValuesByName = <String, Int32List>{
       'i32': Int32List.fromList(<int>[101, 202]),
+    }
+    ..stringValuesByDate = <LocalDate, String>{
+      const LocalDate(2024, 5, 7): 'date-key',
+    }
+    ..boolValuesByName = <String, bool>{'bool': true}
+    ..int8ValuesByName = <String, int>{'int8': -8}
+    ..int16ValuesByName = <String, int>{'int16': -16}
+    ..fixedI32ValuesByName = <String, int>{'fixed-i32': -32}
+    ..varintI32ValuesByName = <String, int>{'varint-i32': 32}
+    ..fixedI64ValuesByName = <String, Int64>{'fixed-i64': Int64(-64)}
+    ..varintI64ValuesByName = <String, Int64>{'varint-i64': Int64(64)}
+    ..taggedI64ValuesByName = <String, Int64>{'tagged-i64': Int64(65)}
+    ..uint8ValuesByName = <String, int>{'uint8': 208}
+    ..uint16ValuesByName = <String, int>{'uint16': 60001}
+    ..fixedU32ValuesByName = <String, int>{'fixed-u32': 1234567892}
+    ..varintU32ValuesByName = <String, int>{'varint-u32': 1234567893}
+    ..fixedU64ValuesByName = <String, Uint64>{'fixed-u64': Uint64(9876543213)}
+    ..varintU64ValuesByName = <String, Uint64>{'varint-u64': 
Uint64(9876543214)}
+    ..taggedU64ValuesByName = <String, Uint64>{'tagged-u64': 
Uint64(9876543215)}
+    ..float32ValuesByName = <String, Float32>{'float32': Float32(3.25)}
+    ..float64ValuesByName = <String, double>{'float64': 6.5}
+    ..timestampValuesByName = <String, Timestamp>{
+      'timestamp': Timestamp.fromDateTime(DateTime.utc(2024, 6, 7, 8, 9, 10)),
+    }
+    ..durationValuesByName = <String, Duration>{
+      'duration': const Duration(seconds: 10),
+    }
+    ..enumValuesByName = <String, example.ExampleState>{
+      'enum': example.ExampleState.failed,
     };
 }
 
@@ -1049,32 +1080,56 @@ void _expectExampleMessageEquals(
   _expectMapEquals(actual.stringValuesByInt8, expected.stringValuesByInt8);
   _expectMapEquals(actual.stringValuesByInt16, expected.stringValuesByInt16);
   _expectMapEquals(
-      actual.stringValuesByFixedI32, expected.stringValuesByFixedI32);
+    actual.stringValuesByFixedI32,
+    expected.stringValuesByFixedI32,
+  );
   _expectMapEquals(
-      actual.stringValuesByVarintI32, expected.stringValuesByVarintI32);
+    actual.stringValuesByVarintI32,
+    expected.stringValuesByVarintI32,
+  );
   _expectMapEquals(
-      actual.stringValuesByFixedI64, expected.stringValuesByFixedI64);
+    actual.stringValuesByFixedI64,
+    expected.stringValuesByFixedI64,
+  );
   _expectMapEquals(
-      actual.stringValuesByVarintI64, expected.stringValuesByVarintI64);
+    actual.stringValuesByVarintI64,
+    expected.stringValuesByVarintI64,
+  );
   _expectMapEquals(
-      actual.stringValuesByTaggedI64, expected.stringValuesByTaggedI64);
+    actual.stringValuesByTaggedI64,
+    expected.stringValuesByTaggedI64,
+  );
   _expectMapEquals(actual.stringValuesByUint8, expected.stringValuesByUint8);
   _expectMapEquals(actual.stringValuesByUint16, expected.stringValuesByUint16);
   _expectMapEquals(
-      actual.stringValuesByFixedU32, expected.stringValuesByFixedU32);
+    actual.stringValuesByFixedU32,
+    expected.stringValuesByFixedU32,
+  );
   _expectMapEquals(
-      actual.stringValuesByVarintU32, expected.stringValuesByVarintU32);
+    actual.stringValuesByVarintU32,
+    expected.stringValuesByVarintU32,
+  );
   _expectMapEquals(
-      actual.stringValuesByFixedU64, expected.stringValuesByFixedU64);
+    actual.stringValuesByFixedU64,
+    expected.stringValuesByFixedU64,
+  );
   _expectMapEquals(
-      actual.stringValuesByVarintU64, expected.stringValuesByVarintU64);
+    actual.stringValuesByVarintU64,
+    expected.stringValuesByVarintU64,
+  );
   _expectMapEquals(
-      actual.stringValuesByTaggedU64, expected.stringValuesByTaggedU64);
+    actual.stringValuesByTaggedU64,
+    expected.stringValuesByTaggedU64,
+  );
   _expectMapEquals(actual.stringValuesByString, expected.stringValuesByString);
   _expectMapEquals(
-      actual.stringValuesByTimestamp, expected.stringValuesByTimestamp);
+    actual.stringValuesByTimestamp,
+    expected.stringValuesByTimestamp,
+  );
   _expectMapEquals(
-      actual.stringValuesByDuration, expected.stringValuesByDuration);
+    actual.stringValuesByDuration,
+    expected.stringValuesByDuration,
+  );
   _expectMapEquals(actual.stringValuesByEnum, expected.stringValuesByEnum);
   _expectMapEquals(actual.float16ValuesByName, expected.float16ValuesByName);
   _expectMapEquals(
@@ -1093,7 +1148,9 @@ void _expectExampleMessageEquals(
   _expectMapEquals(actual.dateValuesByName, expected.dateValuesByName);
   _expectMapEquals(actual.decimalValuesByName, expected.decimalValuesByName);
   expect(
-      actual.messageValuesByName.length, expected.messageValuesByName.length);
+    actual.messageValuesByName.length,
+    expected.messageValuesByName.length,
+  );
   for (final entry in expected.messageValuesByName.entries) {
     final actualValue = actual.messageValuesByName[entry.key];
     expect(actualValue, isNotNull);
@@ -1117,6 +1174,48 @@ void _expectExampleMessageEquals(
     actual.int32ArrayValuesByName,
     expected.int32ArrayValuesByName,
   );
+  _expectMapEquals(actual.stringValuesByDate, expected.stringValuesByDate);
+  _expectMapEquals(actual.boolValuesByName, expected.boolValuesByName);
+  _expectMapEquals(actual.int8ValuesByName, expected.int8ValuesByName);
+  _expectMapEquals(actual.int16ValuesByName, expected.int16ValuesByName);
+  _expectMapEquals(actual.fixedI32ValuesByName, expected.fixedI32ValuesByName);
+  _expectMapEquals(
+    actual.varintI32ValuesByName,
+    expected.varintI32ValuesByName,
+  );
+  _expectMapEquals(actual.fixedI64ValuesByName, expected.fixedI64ValuesByName);
+  _expectMapEquals(
+    actual.varintI64ValuesByName,
+    expected.varintI64ValuesByName,
+  );
+  _expectMapEquals(
+    actual.taggedI64ValuesByName,
+    expected.taggedI64ValuesByName,
+  );
+  _expectMapEquals(actual.uint8ValuesByName, expected.uint8ValuesByName);
+  _expectMapEquals(actual.uint16ValuesByName, expected.uint16ValuesByName);
+  _expectMapEquals(actual.fixedU32ValuesByName, expected.fixedU32ValuesByName);
+  _expectMapEquals(
+    actual.varintU32ValuesByName,
+    expected.varintU32ValuesByName,
+  );
+  _expectMapEquals(actual.fixedU64ValuesByName, expected.fixedU64ValuesByName);
+  _expectMapEquals(
+    actual.varintU64ValuesByName,
+    expected.varintU64ValuesByName,
+  );
+  _expectMapEquals(
+    actual.taggedU64ValuesByName,
+    expected.taggedU64ValuesByName,
+  );
+  _expectMapEquals(actual.float32ValuesByName, expected.float32ValuesByName);
+  _expectMapEquals(actual.float64ValuesByName, expected.float64ValuesByName);
+  _expectMapEquals(
+    actual.timestampValuesByName,
+    expected.timestampValuesByName,
+  );
+  _expectMapEquals(actual.durationValuesByName, expected.durationValuesByName);
+  _expectMapEquals(actual.enumValuesByName, expected.enumValuesByName);
 }
 
 void _expectExampleMessageUnionEquals(
diff --git a/integration_tests/idl_tests/go/idl_roundtrip_test.go 
b/integration_tests/idl_tests/go/idl_roundtrip_test.go
index 02de5689f..ec41e120c 100644
--- a/integration_tests/idl_tests/go/idl_roundtrip_test.go
+++ b/integration_tests/idl_tests/go/idl_roundtrip_test.go
@@ -513,6 +513,27 @@ func buildExampleMessage() example.ExampleMessage {
                Uint8ArrayValuesByName:   map[string][]uint8{"u8": {201, 202}},
                Float32ArrayValuesByName: map[string][]float32{"f32": {1.25, 
2.5}},
                Int32ArrayValuesByName:   map[string][]int32{"i32": {101, 202}},
+               StringValuesByDate:       map[fory.Date]string{{Year: 2024, 
Month: time.May, Day: 7}: "date-key"},
+               BoolValuesByName:         map[string]bool{"bool": true},
+               Int8ValuesByName:         map[string]int8{"int8": -8},
+               Int16ValuesByName:        map[string]int16{"int16": -16},
+               FixedI32ValuesByName:     map[string]int32{"fixed-i32": -32},
+               VarintI32ValuesByName:    map[string]int32{"varint-i32": 32},
+               FixedI64ValuesByName:     map[string]int64{"fixed-i64": -64},
+               VarintI64ValuesByName:    map[string]int64{"varint-i64": 64},
+               TaggedI64ValuesByName:    map[string]int64{"tagged-i64": 65},
+               Uint8ValuesByName:        map[string]uint8{"uint8": 208},
+               Uint16ValuesByName:       map[string]uint16{"uint16": 60001},
+               FixedU32ValuesByName:     map[string]uint32{"fixed-u32": 
1234567892},
+               VarintU32ValuesByName:    map[string]uint32{"varint-u32": 
1234567893},
+               FixedU64ValuesByName:     map[string]uint64{"fixed-u64": 
9876543213},
+               VarintU64ValuesByName:    map[string]uint64{"varint-u64": 
9876543214},
+               TaggedU64ValuesByName:    map[string]uint64{"tagged-u64": 
9876543215},
+               Float32ValuesByName:      map[string]float32{"float32": 3.25},
+               Float64ValuesByName:      map[string]float64{"float64": 6.5},
+               TimestampValuesByName:    map[string]time.Time{"timestamp": 
time.Date(2024, 6, 7, 8, 9, 10, 0, time.UTC)},
+               DurationValuesByName:     map[string]time.Duration{"duration": 
10 * time.Second},
+               EnumValuesByName:         
map[string]example.ExampleState{"enum": example.ExampleStateFailed},
        }
        setOptionalExampleMessageFields(&message)
        return message
@@ -628,6 +649,13 @@ func normalizeExampleMessageForCompare(message 
example.ExampleMessage) example.E
                }
                message.StringValuesByTimestamp = normalized
        }
+       if message.TimestampValuesByName != nil {
+               normalized := make(map[string]time.Time, 
len(message.TimestampValuesByName))
+               for key, value := range message.TimestampValuesByName {
+                       normalized[key] = value.UTC()
+               }
+               message.TimestampValuesByName = normalized
+       }
        value := reflect.ValueOf(&message).Elem()
        for i := 0; i < value.NumField(); i++ {
                field := value.Field(i)
diff --git a/integration_tests/idl_tests/idl/example.fdl 
b/integration_tests/idl_tests/idl/example.fdl
index 7e2960991..4ade5cd85 100644
--- a/integration_tests/idl_tests/idl/example.fdl
+++ b/integration_tests/idl_tests/idl/example.fdl
@@ -145,6 +145,27 @@ message ExampleMessage [id=1500, evolving=true] {
     map<string, array<uint8>> uint8_array_values_by_name = 231;
     map<string, array<float32>> float32_array_values_by_name = 232;
     map<string, array<int32>> int32_array_values_by_name = 233;
+    map<date, string> string_values_by_date = 234;
+    map<string, bool> bool_values_by_name = 236;
+    map<string, int8> int8_values_by_name = 237;
+    map<string, int16> int16_values_by_name = 238;
+    map<string, fixed int32> fixed_i32_values_by_name = 239;
+    map<string, int32> varint_i32_values_by_name = 240;
+    map<string, fixed int64> fixed_i64_values_by_name = 241;
+    map<string, int64> varint_i64_values_by_name = 242;
+    map<string, tagged int64> tagged_i64_values_by_name = 243;
+    map<string, uint8> uint8_values_by_name = 244;
+    map<string, uint16> uint16_values_by_name = 245;
+    map<string, fixed uint32> fixed_u32_values_by_name = 246;
+    map<string, uint32> varint_u32_values_by_name = 247;
+    map<string, fixed uint64> fixed_u64_values_by_name = 248;
+    map<string, uint64> varint_u64_values_by_name = 249;
+    map<string, tagged uint64> tagged_u64_values_by_name = 250;
+    map<string, float32> float32_values_by_name = 251;
+    map<string, float64> float64_values_by_name = 252;
+    map<string, timestamp> timestamp_values_by_name = 253;
+    map<string, duration> duration_values_by_name = 254;
+    map<string, ExampleState> enum_values_by_name = 255;
 }
 
 union ExampleMessageUnion [id=1501] {
@@ -254,4 +275,25 @@ union ExampleMessageUnion [id=1501] {
     map<string, array<uint8>> uint8_array_values_by_name = 231;
     map<string, array<float32>> float32_array_values_by_name = 232;
     map<string, array<int32>> int32_array_values_by_name = 233;
+    map<date, string> string_values_by_date = 234;
+    map<string, bool> bool_values_by_name = 236;
+    map<string, int8> int8_values_by_name = 237;
+    map<string, int16> int16_values_by_name = 238;
+    map<string, fixed int32> fixed_i32_values_by_name = 239;
+    map<string, int32> varint_i32_values_by_name = 240;
+    map<string, fixed int64> fixed_i64_values_by_name = 241;
+    map<string, int64> varint_i64_values_by_name = 242;
+    map<string, tagged int64> tagged_i64_values_by_name = 243;
+    map<string, uint8> uint8_values_by_name = 244;
+    map<string, uint16> uint16_values_by_name = 245;
+    map<string, fixed uint32> fixed_u32_values_by_name = 246;
+    map<string, uint32> varint_u32_values_by_name = 247;
+    map<string, fixed uint64> fixed_u64_values_by_name = 248;
+    map<string, uint64> varint_u64_values_by_name = 249;
+    map<string, tagged uint64> tagged_u64_values_by_name = 250;
+    map<string, float32> float32_values_by_name = 251;
+    map<string, float64> float64_values_by_name = 252;
+    map<string, timestamp> timestamp_values_by_name = 253;
+    map<string, duration> duration_values_by_name = 254;
+    map<string, ExampleState> enum_values_by_name = 255;
 }
diff --git 
a/integration_tests/idl_tests/java/src/test/java/org/apache/fory/idl_tests/IdlRoundTripTest.java
 
b/integration_tests/idl_tests/java/src/test/java/org/apache/fory/idl_tests/IdlRoundTripTest.java
index ae702146a..cd1f2ea0f 100644
--- 
a/integration_tests/idl_tests/java/src/test/java/org/apache/fory/idl_tests/IdlRoundTripTest.java
+++ 
b/integration_tests/idl_tests/java/src/test/java/org/apache/fory/idl_tests/IdlRoundTripTest.java
@@ -27,6 +27,10 @@ import addressbook.Dog;
 import addressbook.Person;
 import addressbook.Person.PhoneNumber;
 import addressbook.Person.PhoneType;
+import any_example.AnyExampleForyRegistration;
+import any_example.AnyHolder;
+import any_example.AnyInner;
+import any_example.AnyUnion;
 import auto_id.AutoIdForyRegistration;
 import auto_id.Envelope;
 import auto_id.Wrapper;
@@ -35,12 +39,6 @@ import collection.NumericCollectionArrayUnion;
 import collection.NumericCollectionUnion;
 import collection.NumericCollections;
 import collection.NumericCollectionsArray;
-import complex_pb.ComplexPbForyRegistration;
-import complex_pb.PrimitiveTypes;
-import any_example.AnyExampleForyRegistration;
-import any_example.AnyHolder;
-import any_example.AnyInner;
-import any_example.AnyUnion;
 import complex_fbs.ComplexFbsForyRegistration;
 import complex_fbs.Container;
 import complex_fbs.Metric;
@@ -48,6 +46,8 @@ import complex_fbs.Note;
 import complex_fbs.Payload;
 import complex_fbs.ScalarPack;
 import complex_fbs.Status;
+import complex_pb.ComplexPbForyRegistration;
+import complex_pb.PrimitiveTypes;
 import evolving1.Evolving1ForyRegistration;
 import evolving1.EvolvingMessage;
 import evolving1.EvolvingSizeMessage;
@@ -64,17 +64,6 @@ import graph.Edge;
 import graph.Graph;
 import graph.GraphForyRegistration;
 import graph.Node;
-import root.MultiHolder;
-import optional_types.AllOptionalTypes;
-import optional_types.OptionalHolder;
-import optional_types.OptionalTypesForyRegistration;
-import optional_types.OptionalUnion;
-import tree.TreeForyRegistration;
-import tree.TreeNode;
-import monster.Color;
-import monster.Monster;
-import monster.MonsterForyRegistration;
-import monster.Vec3;
 import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.IOException;
@@ -94,6 +83,14 @@ import java.util.List;
 import java.util.Map;
 import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
+import monster.Color;
+import monster.Monster;
+import monster.MonsterForyRegistration;
+import monster.Vec3;
+import optional_types.AllOptionalTypes;
+import optional_types.OptionalHolder;
+import optional_types.OptionalTypesForyRegistration;
+import optional_types.OptionalUnion;
 import org.apache.fory.Fory;
 import org.apache.fory.collection.BFloat16List;
 import org.apache.fory.collection.BoolList;
@@ -114,6 +111,9 @@ import org.apache.fory.type.Float16;
 import org.apache.fory.type.Float16Array;
 import org.testng.Assert;
 import org.testng.annotations.Test;
+import root.MultiHolder;
+import tree.TreeForyRegistration;
+import tree.TreeNode;
 
 public class IdlRoundTripTest {
 
@@ -266,8 +266,7 @@ public class IdlRoundTripTest {
     Object fixedSizeDecoded = foryV2.deserialize(fixedSizeBytes);
     Assert.assertTrue(fixedSizeDecoded instanceof evolving2.FixedSizeMessage);
     Assert.assertEquals(
-        ((evolving2.FixedSizeMessage) fixedSizeDecoded).getPayload(),
-        fixedSizeV1.getPayload());
+        ((evolving2.FixedSizeMessage) fixedSizeDecoded).getPayload(), 
fixedSizeV1.getPayload());
     Object fixedSizeRoundTrip = 
foryV1.deserialize(foryV2.serialize(fixedSizeDecoded));
     Assert.assertTrue(fixedSizeRoundTrip instanceof FixedSizeMessage);
     Assert.assertEquals(fixedSizeRoundTrip, fixedSizeV1);
@@ -399,18 +398,15 @@ public class IdlRoundTripTest {
     assertNumericCollectionArrayUnion(arrayUnionDecoded, collectionArrayUnion);
 
     for (String peer : resolvePeers()) {
-      Path collectionsFile =
-          Files.createTempFile("idl-collections-" + peer + "-", ".bin");
+      Path collectionsFile = Files.createTempFile("idl-collections-" + peer + 
"-", ".bin");
       collectionsFile.toFile().deleteOnExit();
       Files.write(collectionsFile, collectionsBytes);
 
-      Path unionFile =
-          Files.createTempFile("idl-collection-union-" + peer + "-", ".bin");
+      Path unionFile = Files.createTempFile("idl-collection-union-" + peer + 
"-", ".bin");
       unionFile.toFile().deleteOnExit();
       Files.write(unionFile, unionBytes);
 
-      Path arrayFile =
-          Files.createTempFile("idl-collections-array-" + peer + "-", ".bin");
+      Path arrayFile = Files.createTempFile("idl-collections-array-" + peer + 
"-", ".bin");
       arrayFile.toFile().deleteOnExit();
       Files.write(arrayFile, arrayBytes);
 
@@ -423,8 +419,7 @@ public class IdlRoundTripTest {
       env.put("DATA_FILE_COLLECTION", 
collectionsFile.toAbsolutePath().toString());
       env.put("DATA_FILE_COLLECTION_UNION", 
unionFile.toAbsolutePath().toString());
       env.put("DATA_FILE_COLLECTION_ARRAY", 
arrayFile.toAbsolutePath().toString());
-      env.put(
-          "DATA_FILE_COLLECTION_ARRAY_UNION", 
arrayUnionFile.toAbsolutePath().toString());
+      env.put("DATA_FILE_COLLECTION_ARRAY_UNION", 
arrayUnionFile.toAbsolutePath().toString());
       PeerCommand command = buildPeerCommand(peer, env, compatible);
       runPeer(command, peer);
 
@@ -667,13 +662,11 @@ public class IdlRoundTripTest {
     Assert.assertEquals(containerDecoded, container);
 
     for (String peer : resolvePeers()) {
-      Path monsterFile =
-          Files.createTempFile("idl-flatbuffers-monster-" + peer + "-", 
".bin");
+      Path monsterFile = Files.createTempFile("idl-flatbuffers-monster-" + 
peer + "-", ".bin");
       monsterFile.toFile().deleteOnExit();
       Files.write(monsterFile, monsterBytes);
 
-      Path containerFile =
-          Files.createTempFile("idl-flatbuffers-test2-" + peer + "-", ".bin");
+      Path containerFile = Files.createTempFile("idl-flatbuffers-test2-" + 
peer + "-", ".bin");
       containerFile.toFile().deleteOnExit();
       Files.write(containerFile, containerBytes);
 
@@ -696,18 +689,11 @@ public class IdlRoundTripTest {
   }
 
   private Fory buildFory(boolean compatible) {
-    return Fory.builder()
-        .withXlang(true)
-        .withCompatible(compatible)
-        .build();
+    return Fory.builder().withXlang(true).withCompatible(compatible).build();
   }
 
   private Fory buildRefFory(boolean compatible) {
-    return Fory.builder()
-        .withXlang(true)
-        .withCompatible(compatible)
-        .withRefTracking(true)
-        .build();
+    return 
Fory.builder().withXlang(true).withCompatible(compatible).withRefTracking(true).build();
   }
 
   private List<String> resolvePeers() {
@@ -802,10 +788,7 @@ public class IdlRoundTripTest {
         workDir = idlRoot.resolve("dart");
         command =
             Arrays.asList(
-                "dart",
-                "test",
-                "--name",
-                "interop file roundtrip hooks when env vars are set");
+                "dart", "test", "--name", "interop file roundtrip hooks when 
env vars are set");
         peerCommand.environment.put("ENABLE_FORY_DEBUG_OUTPUT", "1");
         break;
       default:
@@ -834,9 +817,7 @@ public class IdlRoundTripTest {
       process.waitFor(10, TimeUnit.SECONDS);
       String output = outputCollector.awaitOutput();
       Assert.fail(
-          "Peer process timed out for "
-              + peer
-              + (output.isEmpty() ? "" : "\noutput:\n" + output));
+          "Peer process timed out for " + peer + (output.isEmpty() ? "" : 
"\noutput:\n" + output));
     }
 
     int exitCode = process.exitValue();
@@ -1085,8 +1066,7 @@ public class IdlRoundTripTest {
     message.setDateList(Arrays.asList(LocalDate.of(2024, 1, 1), 
LocalDate.of(2024, 1, 2)));
     message.setTimestampList(
         Arrays.asList(
-            Instant.parse("2024-01-01T00:00:00Z"),
-            Instant.parse("2024-01-02T00:00:00Z")));
+            Instant.parse("2024-01-01T00:00:00Z"), 
Instant.parse("2024-01-02T00:00:00Z")));
     message.setDurationList(Arrays.asList(Duration.ofMillis(1), 
Duration.ofSeconds(2)));
     message.setDecimalList(Arrays.asList(new BigDecimal("1.25"), new 
BigDecimal("2.50")));
     message.setEnumList(Arrays.asList(ExampleState.UNKNOWN, 
ExampleState.FAILED));
@@ -1144,6 +1124,27 @@ public class IdlRoundTripTest {
     message.setUint8ArrayValuesByName(Map.of("u8", new byte[] {(byte) 201, 
(byte) 202}));
     message.setFloat32ArrayValuesByName(Map.of("f32", new float[] {1.25f, 
2.5f}));
     message.setInt32ArrayValuesByName(Map.of("i32", new int[] {101, 202}));
+    message.setStringValuesByDate(Map.of(LocalDate.of(2024, 5, 7), 
"date-key"));
+    message.setBoolValuesByName(Map.of("bool", true));
+    message.setInt8ValuesByName(Map.of("int8", (byte) -8));
+    message.setInt16ValuesByName(Map.of("int16", (short) -16));
+    message.setFixedI32ValuesByName(Map.of("fixed-i32", -32));
+    message.setVarintI32ValuesByName(Map.of("varint-i32", 32));
+    message.setFixedI64ValuesByName(Map.of("fixed-i64", -64L));
+    message.setVarintI64ValuesByName(Map.of("varint-i64", 64L));
+    message.setTaggedI64ValuesByName(Map.of("tagged-i64", 65L));
+    message.setUint8ValuesByName(Map.of("uint8", 208));
+    message.setUint16ValuesByName(Map.of("uint16", 60001));
+    message.setFixedU32ValuesByName(Map.of("fixed-u32", 1234567892L));
+    message.setVarintU32ValuesByName(Map.of("varint-u32", 1234567893L));
+    message.setFixedU64ValuesByName(Map.of("fixed-u64", 9876543213L));
+    message.setVarintU64ValuesByName(Map.of("varint-u64", 9876543214L));
+    message.setTaggedU64ValuesByName(Map.of("tagged-u64", 9876543215L));
+    message.setFloat32ValuesByName(Map.of("float32", 3.25f));
+    message.setFloat64ValuesByName(Map.of("float64", 6.5d));
+    message.setTimestampValuesByName(Map.of("timestamp", 
Instant.parse("2024-06-07T08:09:10Z")));
+    message.setDurationValuesByName(Map.of("duration", 
Duration.ofSeconds(10)));
+    message.setEnumValuesByName(Map.of("enum", ExampleState.FAILED));
     return message;
   }
 
@@ -1159,11 +1160,11 @@ public class IdlRoundTripTest {
         Arrays.asList(new int[] {11, 12}, new int[] {13, 14}));
   }
 
-  private void assertNumericCollectionUnion(
-      Object decoded, NumericCollectionUnion expected) {
+  private void assertNumericCollectionUnion(Object decoded, 
NumericCollectionUnion expected) {
     Assert.assertTrue(decoded instanceof NumericCollectionUnion);
     NumericCollectionUnion union = (NumericCollectionUnion) decoded;
-    Assert.assertEquals(union.getNumericCollectionUnionCase(), 
expected.getNumericCollectionUnionCase());
+    Assert.assertEquals(
+        union.getNumericCollectionUnionCase(), 
expected.getNumericCollectionUnionCase());
     switch (union.getNumericCollectionUnionCase()) {
       case INT32_VALUES:
         Assert.assertEquals(union.getInt32Values(), expected.getInt32Values());
@@ -1178,16 +1179,13 @@ public class IdlRoundTripTest {
     Assert.assertTrue(decoded instanceof NumericCollectionArrayUnion);
     NumericCollectionArrayUnion union = (NumericCollectionArrayUnion) decoded;
     Assert.assertEquals(
-        union.getNumericCollectionArrayUnionCase(),
-        expected.getNumericCollectionArrayUnionCase());
+        union.getNumericCollectionArrayUnionCase(), 
expected.getNumericCollectionArrayUnionCase());
     switch (union.getNumericCollectionArrayUnionCase()) {
       case UINT16_VALUES:
-        Assert.assertTrue(
-            Arrays.equals(union.getUint16Values(), 
expected.getUint16Values()));
+        Assert.assertTrue(Arrays.equals(union.getUint16Values(), 
expected.getUint16Values()));
         break;
       default:
-        Assert.fail(
-            "Unexpected array union case: " + 
union.getNumericCollectionArrayUnionCase());
+        Assert.fail("Unexpected array union case: " + 
union.getNumericCollectionArrayUnionCase());
     }
   }
 
diff --git a/integration_tests/idl_tests/javascript/roundtrip.ts 
b/integration_tests/idl_tests/javascript/roundtrip.ts
index 020747427..23af999e0 100644
--- a/integration_tests/idl_tests/javascript/roundtrip.ts
+++ b/integration_tests/idl_tests/javascript/roundtrip.ts
@@ -147,11 +147,10 @@ function resolveRootSerializer(fory: Fory, bytes: 
Uint8Array): Serializer {
   // serializer detection from the payload, then map back to the local
   // registered serializer when available.
   const detectedSerializer = AnyHelper.detectSerializer(fory.readContext);
-  const resolvedSerializer = (
+  const resolvedSerializer =
     fory.typeResolver.getSerializerByTypeInfo(
       detectedSerializer.getTypeInfo(),
-    ) ?? detectedSerializer
-  );
+    ) ?? detectedSerializer;
   return resolvedSerializer;
 }
 
@@ -514,7 +513,9 @@ function buildExampleMessage(): ExampleMessage {
     stringValuesByVarintU64: new Map([[9876543211n, "varint-u64"]]),
     stringValuesByTaggedU64: new Map([[9876543212n, "tagged-u64"]]),
     stringValuesByString: new Map([["name", "value"]]),
-    stringValuesByTimestamp: new Map([[new Date("2024-03-04T05:06:07Z"), 
"time"]]),
+    stringValuesByTimestamp: new Map([
+      [new Date("2024-03-04T05:06:07Z"), "time"],
+    ]),
     stringValuesByDuration: new Map([[9000, "duration"]]),
     stringValuesByEnum: new Map([[ExampleState.READY, "ready"]]),
     float16ValuesByName: new Map([["f16", 1.25]]),
@@ -529,10 +530,31 @@ function buildExampleMessage(): ExampleMessage {
       ["union", { case: ExampleLeafUnionCase.CODE, value: 42 }],
     ]),
     uint8ArrayValuesByName: new Map([["u8", new Uint8Array([201, 202])]]),
-    float32ArrayValuesByName: new Map([
-      ["f32", new Float32Array([1.25, 2.5])],
-    ]),
+    float32ArrayValuesByName: new Map([["f32", new Float32Array([1.25, 
2.5])]]),
     int32ArrayValuesByName: new Map([["i32", new Int32Array([101, 202])]]),
+    stringValuesByDate: new Map([[buildLocalDate(2024, 5, 7), "date-key"]]),
+    boolValuesByName: new Map([["bool", true]]),
+    int8ValuesByName: new Map([["int8", -8]]),
+    int16ValuesByName: new Map([["int16", -16]]),
+    fixedI32ValuesByName: new Map([["fixed-i32", -32]]),
+    varintI32ValuesByName: new Map([["varint-i32", 32]]),
+    fixedI64ValuesByName: new Map([["fixed-i64", -64n]]),
+    varintI64ValuesByName: new Map([["varint-i64", 64n]]),
+    taggedI64ValuesByName: new Map([["tagged-i64", 65n]]),
+    uint8ValuesByName: new Map([["uint8", 208]]),
+    uint16ValuesByName: new Map([["uint16", 60001]]),
+    fixedU32ValuesByName: new Map([["fixed-u32", 1234567892]]),
+    varintU32ValuesByName: new Map([["varint-u32", 1234567893]]),
+    fixedU64ValuesByName: new Map([["fixed-u64", 9876543213n]]),
+    varintU64ValuesByName: new Map([["varint-u64", 9876543214n]]),
+    taggedU64ValuesByName: new Map([["tagged-u64", 9876543215n]]),
+    float32ValuesByName: new Map([["float32", 3.25]]),
+    float64ValuesByName: new Map([["float64", 6.5]]),
+    timestampValuesByName: new Map([
+      ["timestamp", new Date("2024-06-07T08:09:10Z")],
+    ]),
+    durationValuesByName: new Map([["duration", 10000]]),
+    enumValuesByName: new Map([["enum", ExampleState.FAILED]]),
   };
 }
 
diff --git a/integration_tests/idl_tests/javascript/test/roundtrip.test.ts 
b/integration_tests/idl_tests/javascript/test/roundtrip.test.ts
index 953b79af6..2d3a3b276 100644
--- a/integration_tests/idl_tests/javascript/test/roundtrip.test.ts
+++ b/integration_tests/idl_tests/javascript/test/roundtrip.test.ts
@@ -460,7 +460,9 @@ function buildExampleMessage(): ExampleMessage {
     stringValuesByVarintU64: new Map([[9876543211n, "varint-u64"]]),
     stringValuesByTaggedU64: new Map([[9876543212n, "tagged-u64"]]),
     stringValuesByString: new Map([["name", "value"]]),
-    stringValuesByTimestamp: new Map([[new Date("2024-03-04T05:06:07Z"), 
"time"]]),
+    stringValuesByTimestamp: new Map([
+      [new Date("2024-03-04T05:06:07Z"), "time"],
+    ]),
     stringValuesByDuration: new Map([[9000, "duration"]]),
     stringValuesByEnum: new Map([[ExampleState.READY, "ready"]]),
     float16ValuesByName: new Map([["f16", 1.25]]),
@@ -475,10 +477,31 @@ function buildExampleMessage(): ExampleMessage {
       ["union", { case: ExampleLeafUnionCase.CODE, value: 42 }],
     ]),
     uint8ArrayValuesByName: new Map([["u8", new Uint8Array([201, 202])]]),
-    float32ArrayValuesByName: new Map([
-      ["f32", new Float32Array([1.25, 2.5])],
-    ]),
+    float32ArrayValuesByName: new Map([["f32", new Float32Array([1.25, 
2.5])]]),
     int32ArrayValuesByName: new Map([["i32", new Int32Array([101, 202])]]),
+    stringValuesByDate: new Map([[buildLocalDate(2024, 5, 7), "date-key"]]),
+    boolValuesByName: new Map([["bool", true]]),
+    int8ValuesByName: new Map([["int8", -8]]),
+    int16ValuesByName: new Map([["int16", -16]]),
+    fixedI32ValuesByName: new Map([["fixed-i32", -32]]),
+    varintI32ValuesByName: new Map([["varint-i32", 32]]),
+    fixedI64ValuesByName: new Map([["fixed-i64", -64n]]),
+    varintI64ValuesByName: new Map([["varint-i64", 64n]]),
+    taggedI64ValuesByName: new Map([["tagged-i64", 65n]]),
+    uint8ValuesByName: new Map([["uint8", 208]]),
+    uint16ValuesByName: new Map([["uint16", 60001]]),
+    fixedU32ValuesByName: new Map([["fixed-u32", 1234567892]]),
+    varintU32ValuesByName: new Map([["varint-u32", 1234567893]]),
+    fixedU64ValuesByName: new Map([["fixed-u64", 9876543213n]]),
+    varintU64ValuesByName: new Map([["varint-u64", 9876543214n]]),
+    taggedU64ValuesByName: new Map([["tagged-u64", 9876543215n]]),
+    float32ValuesByName: new Map([["float32", 3.25]]),
+    float64ValuesByName: new Map([["float64", 6.5]]),
+    timestampValuesByName: new Map([
+      ["timestamp", new Date("2024-06-07T08:09:10Z")],
+    ]),
+    durationValuesByName: new Map([["duration", 10000]]),
+    enumValuesByName: new Map([["enum", ExampleState.FAILED]]),
   };
 }
 
diff --git a/integration_tests/idl_tests/python/idl_tests/roundtrip.py 
b/integration_tests/idl_tests/python/idl_tests/roundtrip.py
index 76bdb3731..942386c05 100644
--- a/integration_tests/idl_tests/python/idl_tests/roundtrip.py
+++ b/integration_tests/idl_tests/python/idl_tests/roundtrip.py
@@ -540,6 +540,31 @@ def build_example_message() -> "example.ExampleMessage":
         union_values_by_name={"union": example.ExampleLeafUnion.code(42)},
         uint8_array_values_by_name={"u8": np.array([201, 202], 
dtype=np.uint8)},
         float32_array_values_by_name={"f32": np.array([1.25, 2.5], 
dtype=np.float32)},
+        string_values_by_date={datetime.date(2024, 5, 7): "date-key"},
+        bool_values_by_name={"bool": True},
+        int8_values_by_name={"int8": -8},
+        int16_values_by_name={"int16": -16},
+        fixed_i32_values_by_name={"fixed-i32": -32},
+        varint_i32_values_by_name={"varint-i32": 32},
+        fixed_i64_values_by_name={"fixed-i64": -64},
+        varint_i64_values_by_name={"varint-i64": 64},
+        tagged_i64_values_by_name={"tagged-i64": 65},
+        uint8_values_by_name={"uint8": 208},
+        uint16_values_by_name={"uint16": 60001},
+        fixed_u32_values_by_name={"fixed-u32": 1234567892},
+        varint_u32_values_by_name={"varint-u32": 1234567893},
+        fixed_u64_values_by_name={"fixed-u64": 9876543213},
+        varint_u64_values_by_name={"varint-u64": 9876543214},
+        tagged_u64_values_by_name={"tagged-u64": 9876543215},
+        float32_values_by_name={"float32": 3.25},
+        float64_values_by_name={"float64": 6.5},
+        timestamp_values_by_name={
+            "timestamp": datetime.datetime(
+                2024, 6, 7, 8, 9, 10, tzinfo=datetime.timezone.utc
+            )
+        },
+        duration_values_by_name={"duration": datetime.timedelta(seconds=10)},
+        enum_values_by_name={"enum": example.ExampleState.FAILED},
     )
     fields = example.ExampleMessage.__dataclass_fields__
     if "uint8_array_list" in fields:
diff --git a/integration_tests/idl_tests/rust/tests/idl_roundtrip.rs 
b/integration_tests/idl_tests/rust/tests/idl_roundtrip.rs
index 201c5359f..1e1b7b1c2 100644
--- a/integration_tests/idl_tests/rust/tests/idl_roundtrip.rs
+++ b/integration_tests/idl_tests/rust/tests/idl_roundtrip.rs
@@ -32,7 +32,7 @@ use idl_tests::generated::collection::{
     self, NumericCollectionArrayUnion, NumericCollectionUnion, 
NumericCollections,
     NumericCollectionsArray,
 };
-use idl_tests::generated::complex_fbs::{self, Container, Note, Payload, 
ScalarPack, Status};
+use idl_tests::generated::complex_fbs::{self, Container, Payload, ScalarPack, 
Status};
 use idl_tests::generated::complex_pb::{self, PrimitiveTypes};
 use idl_tests::generated::evolving1;
 use idl_tests::generated::evolving2;
@@ -54,11 +54,7 @@ fn build_address_book() -> AddressBook {
         phone_type: PhoneType::Work,
     };
 
-    let mut pet = Animal::Dog(Dog {
-        name: "Rex".to_string(),
-        bark_volume: 5,
-    });
-    pet = Animal::Cat(Cat {
+    let pet = Animal::Cat(Cat {
         name: "Mimi".to_string(),
         lives: 9,
     });
@@ -152,8 +148,7 @@ fn test_to_bytes_from_bytes() {
 }
 
 fn build_primitive_types() -> PrimitiveTypes {
-    let mut contact = 
complex_pb::primitive_types::Contact::Email("[email protected]".to_string());
-    contact = complex_pb::primitive_types::Contact::Phone(12345);
+    let contact = complex_pb::primitive_types::Contact::Phone(12345);
 
     PrimitiveTypes {
         bool_value: true,
@@ -246,10 +241,7 @@ fn build_container() -> Container {
         d: 2.5,
         ok: true,
     };
-    let mut payload = Payload::Note(Note {
-        text: "alpha".to_string(),
-    });
-    payload = Payload::Metric(complex_fbs::Metric { value: 42.0 });
+    let payload = Payload::Metric(complex_fbs::Metric { value: 42.0 });
 
     Container {
         id: 9876543210,
@@ -519,6 +511,39 @@ fn build_example_message() -> ExampleMessage {
         uint8_array_values_by_name: HashMap::from([("u8".to_string(), 
vec![201, 202])]),
         float32_array_values_by_name: HashMap::from([("f32".to_string(), 
vec![1.25, 2.5])]),
         int32_array_values_by_name: HashMap::from([("i32".to_string(), 
vec![101, 202])]),
+        string_values_by_date: HashMap::from([(
+            NaiveDate::from_ymd_opt(2024, 5, 7).unwrap(),
+            "date-key".to_string(),
+        )]),
+        bool_values_by_name: HashMap::from([("bool".to_string(), true)]),
+        int8_values_by_name: HashMap::from([("int8".to_string(), -8)]),
+        int16_values_by_name: HashMap::from([("int16".to_string(), -16)]),
+        fixed_i32_values_by_name: HashMap::from([("fixed-i32".to_string(), 
-32)]),
+        varint_i32_values_by_name: HashMap::from([("varint-i32".to_string(), 
32)]),
+        fixed_i64_values_by_name: HashMap::from([("fixed-i64".to_string(), 
-64)]),
+        varint_i64_values_by_name: HashMap::from([("varint-i64".to_string(), 
64)]),
+        tagged_i64_values_by_name: HashMap::from([("tagged-i64".to_string(), 
65)]),
+        uint8_values_by_name: HashMap::from([("uint8".to_string(), 208)]),
+        uint16_values_by_name: HashMap::from([("uint16".to_string(), 60001)]),
+        fixed_u32_values_by_name: HashMap::from([("fixed-u32".to_string(), 
1234567892)]),
+        varint_u32_values_by_name: HashMap::from([("varint-u32".to_string(), 
1234567893)]),
+        fixed_u64_values_by_name: HashMap::from([("fixed-u64".to_string(), 
9876543213)]),
+        varint_u64_values_by_name: HashMap::from([("varint-u64".to_string(), 
9876543214)]),
+        tagged_u64_values_by_name: HashMap::from([("tagged-u64".to_string(), 
9876543215)]),
+        float32_values_by_name: HashMap::from([("float32".to_string(), 3.25)]),
+        float64_values_by_name: HashMap::from([("float64".to_string(), 6.5)]),
+        timestamp_values_by_name: HashMap::from([(
+            "timestamp".to_string(),
+            NaiveDate::from_ymd_opt(2024, 6, 7)
+                .unwrap()
+                .and_hms_opt(8, 9, 10)
+                .unwrap(),
+        )]),
+        duration_values_by_name: HashMap::from([(
+            "duration".to_string(),
+            chrono::Duration::seconds(10),
+        )]),
+        enum_values_by_name: HashMap::from([("enum".to_string(), 
ExampleState::Failed)]),
     }
 }
 
diff --git 
a/integration_tests/idl_tests/swift/idl_package/Tests/IdlRoundTripTests/IdlRoundTripTests.swift
 
b/integration_tests/idl_tests/swift/idl_package/Tests/IdlRoundTripTests/IdlRoundTripTests.swift
index 4c1a73840..7e80b7aad 100644
--- 
a/integration_tests/idl_tests/swift/idl_package/Tests/IdlRoundTripTests/IdlRoundTripTests.swift
+++ 
b/integration_tests/idl_tests/swift/idl_package/Tests/IdlRoundTripTests/IdlRoundTripTests.swift
@@ -562,7 +562,28 @@ final class IdlRoundTripTests: XCTestCase {
             unionValuesByName: ["union": .code(42)],
             uint8ArrayValuesByName: ["u8": [201, 202]],
             float32ArrayValuesByName: ["f32": [1.25, 2.5]],
-            int32ArrayValuesByName: ["i32": [101, 202]]
+            int32ArrayValuesByName: ["i32": [101, 202]],
+            stringValuesByDate: [try! LocalDate(year: 2024, month: 5, day: 7): 
"date-key"],
+            boolValuesByName: ["bool": true],
+            int8ValuesByName: ["int8": -8],
+            int16ValuesByName: ["int16": -16],
+            fixedI32ValuesByName: ["fixed-i32": -32],
+            varintI32ValuesByName: ["varint-i32": 32],
+            fixedI64ValuesByName: ["fixed-i64": -64],
+            varintI64ValuesByName: ["varint-i64": 64],
+            taggedI64ValuesByName: ["tagged-i64": 65],
+            uint8ValuesByName: ["uint8": 208],
+            uint16ValuesByName: ["uint16": 60001],
+            fixedU32ValuesByName: ["fixed-u32": 1234567892],
+            varintU32ValuesByName: ["varint-u32": 1234567893],
+            fixedU64ValuesByName: ["fixed-u64": 9876543213],
+            varintU64ValuesByName: ["varint-u64": 9876543214],
+            taggedU64ValuesByName: ["tagged-u64": 9876543215],
+            float32ValuesByName: ["float32": 3.25],
+            float64ValuesByName: ["float64": 6.5],
+            timestampValuesByName: ["timestamp": Date(timeIntervalSince1970: 
1717747750)],
+            durationValuesByName: ["duration": .seconds(10)],
+            enumValuesByName: ["enum": .failed]
         )
     }
 
@@ -618,6 +639,27 @@ final class IdlRoundTripTests: XCTestCase {
         XCTAssertEqual(actual.uint8ArrayValuesByName, 
expected.uint8ArrayValuesByName)
         XCTAssertEqual(actual.float32ArrayValuesByName, 
expected.float32ArrayValuesByName)
         XCTAssertEqual(actual.int32ArrayValuesByName, 
expected.int32ArrayValuesByName)
+        XCTAssertEqual(actual.stringValuesByDate, expected.stringValuesByDate)
+        XCTAssertEqual(actual.boolValuesByName, expected.boolValuesByName)
+        XCTAssertEqual(actual.int8ValuesByName, expected.int8ValuesByName)
+        XCTAssertEqual(actual.int16ValuesByName, expected.int16ValuesByName)
+        XCTAssertEqual(actual.fixedI32ValuesByName, 
expected.fixedI32ValuesByName)
+        XCTAssertEqual(actual.varintI32ValuesByName, 
expected.varintI32ValuesByName)
+        XCTAssertEqual(actual.fixedI64ValuesByName, 
expected.fixedI64ValuesByName)
+        XCTAssertEqual(actual.varintI64ValuesByName, 
expected.varintI64ValuesByName)
+        XCTAssertEqual(actual.taggedI64ValuesByName, 
expected.taggedI64ValuesByName)
+        XCTAssertEqual(actual.uint8ValuesByName, expected.uint8ValuesByName)
+        XCTAssertEqual(actual.uint16ValuesByName, expected.uint16ValuesByName)
+        XCTAssertEqual(actual.fixedU32ValuesByName, 
expected.fixedU32ValuesByName)
+        XCTAssertEqual(actual.varintU32ValuesByName, 
expected.varintU32ValuesByName)
+        XCTAssertEqual(actual.fixedU64ValuesByName, 
expected.fixedU64ValuesByName)
+        XCTAssertEqual(actual.varintU64ValuesByName, 
expected.varintU64ValuesByName)
+        XCTAssertEqual(actual.taggedU64ValuesByName, 
expected.taggedU64ValuesByName)
+        XCTAssertEqual(actual.float32ValuesByName, 
expected.float32ValuesByName)
+        XCTAssertEqual(actual.float64ValuesByName, 
expected.float64ValuesByName)
+        XCTAssertEqual(actual.timestampValuesByName, 
expected.timestampValuesByName)
+        XCTAssertEqual(actual.durationValuesByName, 
expected.durationValuesByName)
+        XCTAssertEqual(actual.enumValuesByName, expected.enumValuesByName)
     }
 
     private func buildOptionalHolder() -> OptionalTypes.OptionalHolder {
diff --git 
a/kotlin/src/test/kotlin/org/apache/fory/serializer/kotlin/TypeUseAnnotationTest.kt
 
b/kotlin/src/test/kotlin/org/apache/fory/serializer/kotlin/TypeUseAnnotationTest.kt
new file mode 100644
index 000000000..f6c68565b
--- /dev/null
+++ 
b/kotlin/src/test/kotlin/org/apache/fory/serializer/kotlin/TypeUseAnnotationTest.kt
@@ -0,0 +1,45 @@
+/*
+ * 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.serializer.kotlin
+
+import org.apache.fory.annotation.Int32Type
+import org.apache.fory.annotation.UInt32Type
+import org.apache.fory.annotation.UInt64Type
+import org.apache.fory.config.Int32Encoding
+import org.testng.Assert
+import org.testng.annotations.Test
+
+class TypeUseAnnotationTest {
+  private class TypeUseCarrier(
+    val fixedId: @Int32Type(encoding = Int32Encoding.FIXED) Int = 1,
+    val unsignedId: @UInt32Type Int = 2,
+    val unsignedValues: List<@UInt64Type Long> = listOf(3L),
+    val unsignedArrayValues: Array<@UInt32Type Int> = arrayOf(4),
+  )
+
+  @Test
+  fun testJavaScalarAnnotationsCompileAtKotlinTypeUseSites() {
+    val carrier = TypeUseCarrier()
+    Assert.assertEquals(carrier.fixedId, 1)
+    Assert.assertEquals(carrier.unsignedId, 2)
+    Assert.assertEquals(carrier.unsignedValues, listOf(3L))
+    Assert.assertEquals(carrier.unsignedArrayValues.toList(), listOf(4))
+  }
+}
diff --git a/rust/fory/src/lib.rs b/rust/fory/src/lib.rs
index ed66e6f86..c96e46baf 100644
--- a/rust/fory/src/lib.rs
+++ b/rust/fory/src/lib.rs
@@ -806,7 +806,7 @@
 //!
 //! - External types from other crates that you can't modify
 //! - Types with special serialization requirements
-//! - Legacy data format compatibility
+//! - Existing external binary format interoperability
 //! - Performance-critical custom encoding
 //! - Complex types that require special handling
 //!
diff --git 
a/scala/src/test/scala/org/apache/fory/serializer/scala/TypeUseAnnotationTest.scala
 
b/scala/src/test/scala/org/apache/fory/serializer/scala/TypeUseAnnotationTest.scala
new file mode 100644
index 000000000..4032eaee1
--- /dev/null
+++ 
b/scala/src/test/scala/org/apache/fory/serializer/scala/TypeUseAnnotationTest.scala
@@ -0,0 +1,42 @@
+/*
+ * 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.serializer.scala
+
+import java.util.Arrays
+import org.apache.fory.annotation.{Int32Type, UInt32Type, UInt64Type}
+import org.scalatest.matchers.should.Matchers
+import org.scalatest.wordspec.AnyWordSpec
+
+final class ScalaTypeUseCarrier {
+  val fixedId: Int @Int32Type = 1
+  val unsignedId: Int @UInt32Type = 2
+  val unsignedValues: java.util.List[Long @UInt64Type] = Arrays.asList(3L)
+}
+
+class TypeUseAnnotationTest extends AnyWordSpec with Matchers {
+  "Java scalar annotations" should {
+    "compile at Scala type positions" in {
+      val carrier = new ScalaTypeUseCarrier
+      carrier.fixedId shouldBe 1
+      carrier.unsignedId shouldBe 2
+      carrier.unsignedValues shouldEqual Arrays.asList(3L)
+    }
+  }
+}


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

Reply via email to