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 e53cbf278 feat(java): generate java List for primitive array (#3247)
e53cbf278 is described below

commit e53cbf278ceefc3fd413287fdb0e4d4a7aaecd12
Author: Shawn Yang <[email protected]>
AuthorDate: Sat Jan 31 14:05:25 2026 +0800

    feat(java): generate java List for primitive array (#3247)
    
    ## Why?
    
    Default Java codegen for repeated integer fields should prefer
    Int*/Uint*List for stable type identity while keeping array mode
    available, and the runtime/tests need to treat these list types as
    built-in for cross-language compatibility.
    
    
    ## What does this PR do?
    
    - Add `java_array` field option and switch Java generator defaults for
    repeated integer fields to Int*/Uint*List while preserving array
    annotations when opted in.
    - Extend FDL parsing to allow union repeated fields/options and improve
    ref option handling for list/map fields.
    - Treat primitive list types as builtin/primitive arrays in Java runtime
    (FieldTypes/resolvers/fingerprint) and add union case conversion between
    lists and arrays.
    - Update C++/Go serializers for unsigned/float16 slice handling aligned
    with the array protocol.
    - Add collection IDL and cross-language roundtrip tests, plus Java
    array/list compatibility test.
    
    
    ## Related issues
    
    Closes #3246
    ## Does this PR introduce any user-facing change?
    
    Yes. Java codegen defaults for repeated integer fields now use
    Int*/Uint*List unless `use_java_array=true` is specified; union field
    options and repeated union cases are now supported.
    
    
    - [ ] Does this PR introduce any public API change?
    - [ ] Does this PR introduce any binary protocol compatibility change?
    
    ## Benchmark
---
 .gitignore                                         |   4 +
 compiler/fory_compiler/frontend/fdl/parser.py      |  12 +-
 compiler/fory_compiler/generators/java.py          | 101 +++++++-
 compiler/fory_compiler/generators/rust.py          |   6 +
 cpp/fory/serialization/unsigned_serializer.h       | 118 ++++++----
 go/fory/reader.go                                  |  42 ++++
 go/fory/slice_primitive.go                         | 232 ++++++++++++++++++-
 go/fory/struct.go                                  |  36 +++
 go/fory/type_resolver.go                           |   8 +
 go/fory/types.go                                   |  20 +-
 go/fory/writer.go                                  |  45 ++++
 integration_tests/idl_tests/cpp/main.cc            | 137 +++++++++++
 integration_tests/idl_tests/generate_idl.py        |   2 +
 .../idl_tests/go/idl_roundtrip_test.go             | 205 +++++++++++++++++
 integration_tests/idl_tests/idl/collection.fdl     |  70 ++++++
 .../apache/fory/idl_tests/IdlRoundTripTest.java    | 178 ++++++++++++++-
 .../idl_tests/python/src/idl_tests/roundtrip.py    | 177 ++++++++++++++
 integration_tests/idl_tests/rust/src/lib.rs        |   1 +
 .../idl_tests/rust/tests/idl_roundtrip.rs          | 115 ++++++++++
 .../java/org/apache/fory/collection/Int16List.java |  26 ++-
 .../java/org/apache/fory/collection/Int32List.java |  26 ++-
 .../java/org/apache/fory/collection/Int64List.java |  26 ++-
 .../java/org/apache/fory/collection/Int8List.java  |  26 ++-
 .../org/apache/fory/collection/Uint16List.java     |  26 ++-
 .../org/apache/fory/collection/Uint32List.java     |  26 ++-
 .../org/apache/fory/collection/Uint64List.java     |  26 ++-
 .../java/org/apache/fory/collection/Uint8List.java |  26 ++-
 .../main/java/org/apache/fory/meta/FieldTypes.java |  48 ++++
 .../org/apache/fory/resolver/ClassResolver.java    |   6 +
 .../org/apache/fory/resolver/TypeResolver.java     |  13 +-
 .../org/apache/fory/resolver/XtypeResolver.java    |   9 +
 .../org/apache/fory/serializer/Serializers.java    |  16 ++
 .../apache/fory/serializer/UnionSerializer.java    | 253 +++++++++++++--------
 .../apache/fory/serializer/struct/Fingerprint.java |  52 +++++
 .../main/java/org/apache/fory/type/TypeUtils.java  |  28 +++
 .../fory/serializer/PrimitiveSerializersTest.java  | 123 ++++++++++
 36 files changed, 2108 insertions(+), 157 deletions(-)

diff --git a/.gitignore b/.gitignore
index 3a07acae7..142f7b8f0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -49,9 +49,11 @@ integration_tests/idl_tests/go/monster/
 integration_tests/idl_tests/go/optional_types/
 integration_tests/idl_tests/go/tree/
 integration_tests/idl_tests/go/graph/
+integration_tests/idl_tests/go/collection/
 integration_tests/idl_tests/java/src/main/
 integration_tests/idl_tests/go/root/
 integration_tests/idl_tests/go/addressbook/
+integration_tests/idl_tests/java/src/main/java/collection/
 integration_tests/idl_tests/java/src/main/java/addressbook/
 integration_tests/idl_tests/java/src/main/java/complex_fbs/
 integration_tests/idl_tests/java/src/main/java/complex_pb/
@@ -67,6 +69,7 @@ integration_tests/idl_tests/python/src/complex_fbs.py
 integration_tests/idl_tests/python/src/complex_pb.py
 integration_tests/idl_tests/python/src/monster.py
 integration_tests/idl_tests/python/src/optional_types.py
+integration_tests/idl_tests/python/src/collection.py
 integration_tests/idl_tests/python/src/tree.py
 integration_tests/idl_tests/python/src/graph.py
 integration_tests/idl_tests/python/src/root.py
@@ -77,6 +80,7 @@ integration_tests/idl_tests/rust/src/complex_fbs.rs
 integration_tests/idl_tests/rust/src/complex_pb.rs
 integration_tests/idl_tests/rust/src/monster.rs
 integration_tests/idl_tests/rust/src/optional_types.rs
+integration_tests/idl_tests/rust/src/collection.rs
 integration_tests/idl_tests/rust/src/tree.rs
 integration_tests/idl_tests/rust/src/graph.rs
 integration_tests/idl_tests/rust/src/root.rs
diff --git a/compiler/fory_compiler/frontend/fdl/parser.py 
b/compiler/fory_compiler/frontend/fdl/parser.py
index 197d11e6e..feb627c40 100644
--- a/compiler/fory_compiler/frontend/fdl/parser.py
+++ b/compiler/fory_compiler/frontend/fdl/parser.py
@@ -67,6 +67,7 @@ KNOWN_FIELD_OPTIONS: Set[str] = {
     "nullable",
     "thread_safe_pointer",
     "weak_ref",
+    "java_array",
 }
 
 KNOWN_REF_OPTIONS: Set[str] = {
@@ -530,17 +531,23 @@ class Parser:
 
         if self.check(TokenType.OPTIONAL) or self.check(TokenType.REF):
             raise self.error("Union cases do not support optional/ref 
modifiers")
+
+        repeated = False
         if self.check(TokenType.REPEATED):
-            raise self.error("Union cases do not support repeated modifiers")
+            self.advance()
+            repeated = True
 
         field_type = self.parse_type()
+        if repeated:
+            field_type = ListType(field_type, 
location=self.make_location(start))
         name = self.consume(TokenType.IDENT, "Expected union case name").value
         self.consume(TokenType.EQUALS, "Expected '=' after union case name")
         number_token = self.consume(TokenType.INT, "Expected union case id")
         number = int(number_token.value)
 
+        field_options = {}
         if self.check(TokenType.LBRACKET):
-            raise self.error("Union cases do not support field options")
+            field_options = self.parse_field_options(name)
 
         self.consume(TokenType.SEMI, "Expected ';' after union case")
 
@@ -549,6 +556,7 @@ class Parser:
             field_type=field_type,
             number=number,
             tag_id=number,
+            options=field_options,
             line=start.line,
             column=start.column,
             location=self.make_location(start),
diff --git a/compiler/fory_compiler/generators/java.py 
b/compiler/fory_compiler/generators/java.py
index 47f2e7cf7..11c479e10 100644
--- a/compiler/fory_compiler/generators/java.py
+++ b/compiler/fory_compiler/generators/java.py
@@ -283,6 +283,24 @@ class JavaGenerator(BaseGenerator):
         PrimitiveKind.FLOAT64: "double[]",
     }
 
+    # Primitive list types for repeated integer fields (default mode)
+    PRIMITIVE_LIST_MAP = {
+        PrimitiveKind.INT8: "Int8List",
+        PrimitiveKind.INT16: "Int16List",
+        PrimitiveKind.INT32: "Int32List",
+        PrimitiveKind.VARINT32: "Int32List",
+        PrimitiveKind.INT64: "Int64List",
+        PrimitiveKind.VARINT64: "Int64List",
+        PrimitiveKind.TAGGED_INT64: "Int64List",
+        PrimitiveKind.UINT8: "Uint8List",
+        PrimitiveKind.UINT16: "Uint16List",
+        PrimitiveKind.UINT32: "Uint32List",
+        PrimitiveKind.VAR_UINT32: "Uint32List",
+        PrimitiveKind.UINT64: "Uint64List",
+        PrimitiveKind.VAR_UINT64: "Uint64List",
+        PrimitiveKind.TAGGED_UINT64: "Uint64List",
+    }
+
     def generate(self) -> List[GeneratedFile]:
         """Generate Java files for the schema.
 
@@ -588,6 +606,7 @@ class JavaGenerator(BaseGenerator):
                 imports,
                 field.element_optional,
                 field.element_ref,
+                field,
             )
 
     def has_array_field_recursive(self, message: Message) -> bool:
@@ -701,6 +720,17 @@ class JavaGenerator(BaseGenerator):
             case_enum_name = self.to_upper_snake_case(field.name)
             case_type = self.get_union_case_type(field)
             cast_type = self.get_union_case_cast_type(field)
+            wrap_array_type: Optional[str] = None
+            wrap_list_type: Optional[str] = None
+            if (
+                isinstance(field.field_type, ListType)
+                and isinstance(field.field_type.element_type, PrimitiveType)
+                and field.field_type.element_type.kind in 
self.PRIMITIVE_LIST_MAP
+                and not self.java_array(field)
+            ):
+                kind = field.field_type.element_type.kind
+                wrap_list_type = self.PRIMITIVE_LIST_MAP[kind]
+                wrap_array_type = self.PRIMITIVE_ARRAY_MAP[kind]
 
             lines.append(f"{ind}    public boolean has{case_name}() {{")
             lines.append(
@@ -716,6 +746,12 @@ class JavaGenerator(BaseGenerator):
                 f'{ind}            throw new 
IllegalStateException("{union.name} is not {case_enum_name}");'
             )
             lines.append(f"{ind}        }}")
+            if wrap_array_type and wrap_list_type:
+                lines.append(f"{ind}        if (value instanceof 
{wrap_array_type}) {{")
+                lines.append(
+                    f"{ind}            value = new 
{wrap_list_type}(({wrap_array_type}) value);"
+                )
+                lines.append(f"{ind}        }}")
             lines.append(f"{ind}        return ({cast_type}) value;")
             lines.append(f"{ind}    }}")
             lines.append("")
@@ -765,6 +801,7 @@ class JavaGenerator(BaseGenerator):
             False,
             field.element_optional,
             field.element_ref,
+            field,
         )
 
     def get_union_case_cast_type(self, field: Field) -> str:
@@ -809,6 +846,34 @@ class JavaGenerator(BaseGenerator):
             }
             return primitive_type_ids.get(kind, "Types.UNKNOWN")
         if isinstance(field.field_type, ListType):
+            if (
+                isinstance(field.field_type.element_type, PrimitiveType)
+                and not field.element_optional
+                and not field.element_ref
+            ):
+                kind = field.field_type.element_type.kind
+                array_type_ids = {
+                    PrimitiveKind.BOOL: "Types.BOOL_ARRAY",
+                    PrimitiveKind.INT8: "Types.INT8_ARRAY",
+                    PrimitiveKind.INT16: "Types.INT16_ARRAY",
+                    PrimitiveKind.INT32: "Types.INT32_ARRAY",
+                    PrimitiveKind.VARINT32: "Types.INT32_ARRAY",
+                    PrimitiveKind.INT64: "Types.INT64_ARRAY",
+                    PrimitiveKind.VARINT64: "Types.INT64_ARRAY",
+                    PrimitiveKind.TAGGED_INT64: "Types.INT64_ARRAY",
+                    PrimitiveKind.UINT8: "Types.UINT8_ARRAY",
+                    PrimitiveKind.UINT16: "Types.UINT16_ARRAY",
+                    PrimitiveKind.UINT32: "Types.UINT32_ARRAY",
+                    PrimitiveKind.VAR_UINT32: "Types.UINT32_ARRAY",
+                    PrimitiveKind.UINT64: "Types.UINT64_ARRAY",
+                    PrimitiveKind.VAR_UINT64: "Types.UINT64_ARRAY",
+                    PrimitiveKind.TAGGED_UINT64: "Types.UINT64_ARRAY",
+                    PrimitiveKind.FLOAT16: "Types.FLOAT16_ARRAY",
+                    PrimitiveKind.FLOAT32: "Types.FLOAT32_ARRAY",
+                    PrimitiveKind.FLOAT64: "Types.FLOAT64_ARRAY",
+                }
+                if kind in array_type_ids:
+                    return array_type_ids[kind]
             return "Types.LIST"
         if isinstance(field.field_type, MapType):
             return "Types.MAP"
@@ -983,6 +1048,7 @@ class JavaGenerator(BaseGenerator):
             nullable,
             field.element_optional,
             field.element_ref,
+            field,
         )
 
         lines.append(f"private {java_type} {self.to_camel_case(field.name)};")
@@ -1003,6 +1069,7 @@ class JavaGenerator(BaseGenerator):
             nullable,
             field.element_optional,
             field.element_ref,
+            field,
         )
         field_name = self.to_camel_case(field.name)
         pascal_name = self.to_pascal_case(field.name)
@@ -1027,6 +1094,7 @@ class JavaGenerator(BaseGenerator):
         nullable: bool = False,
         element_optional: bool = False,
         element_ref: bool = False,
+        field: Optional[Field] = None,
     ) -> str:
         """Generate Java type string."""
         if isinstance(field_type, PrimitiveType):
@@ -1043,13 +1111,18 @@ class JavaGenerator(BaseGenerator):
             return field_type.name
 
         elif isinstance(field_type, ListType):
-            # Use primitive arrays for numeric types
+            # Use primitive arrays for numeric types, or primitive lists by 
default for integers
             if isinstance(field_type.element_type, PrimitiveType):
                 if (
                     field_type.element_type.kind in self.PRIMITIVE_ARRAY_MAP
                     and not element_optional
                     and not element_ref
                 ):
+                    if (
+                        field_type.element_type.kind in self.PRIMITIVE_LIST_MAP
+                        and not self.java_array(field)
+                    ):
+                        return 
self.PRIMITIVE_LIST_MAP[field_type.element_type.kind]
                     return 
self.PRIMITIVE_ARRAY_MAP[field_type.element_type.kind]
             element_type = self.generate_type(field_type.element_type, True)
             if self.is_ref_target_type(field_type.element_type):
@@ -1075,6 +1148,7 @@ class JavaGenerator(BaseGenerator):
         imports: Set[str],
         element_optional: bool = False,
         element_ref: bool = False,
+        field: Optional[Field] = None,
     ):
         """Collect required imports for a field type."""
         if isinstance(field_type, PrimitiveType):
@@ -1091,7 +1165,15 @@ class JavaGenerator(BaseGenerator):
                     and not element_optional
                     and not element_ref
                 ):
-                    return  # No import needed for primitive arrays
+                    if (
+                        field_type.element_type.kind in self.PRIMITIVE_LIST_MAP
+                        and not self.java_array(field)
+                    ):
+                        imports.add(
+                            "org.apache.fory.collection."
+                            + 
self.PRIMITIVE_LIST_MAP[field_type.element_type.kind]
+                        )
+                    return  # No import needed for primitive arrays or 
primitive lists
             imports.add("java.util.List")
             if self.is_ref_target_type(field_type.element_type):
                 imports.add("org.apache.fory.annotation.Ref")
@@ -1115,6 +1197,7 @@ class JavaGenerator(BaseGenerator):
             imports,
             field.element_optional,
             field.element_ref,
+            field,
         )
         self.collect_integer_imports(field.field_type, imports)
         self.collect_array_imports(field, imports)
@@ -1127,10 +1210,17 @@ class JavaGenerator(BaseGenerator):
         resolved = self.schema.get_type(field_type.name)
         return isinstance(resolved, (Message, Union))
 
+    def java_array(self, field: Optional[Field]) -> bool:
+        if field is None:
+            return False
+        return bool(field.options.get("java_array"))
+
     def collect_array_imports(self, field: Field, imports: Set[str]) -> None:
         """Collect imports for primitive array type annotations."""
         if not isinstance(field.field_type, ListType):
             return
+        if not self.java_array(field):
+            return
         if field.element_optional or field.element_ref:
             return
         element_type = field.field_type.element_type
@@ -1207,6 +1297,8 @@ class JavaGenerator(BaseGenerator):
         """Return array type annotation for primitive list fields."""
         if not isinstance(field.field_type, ListType):
             return None
+        if not self.java_array(field):
+            return None
         if field.element_optional or field.element_ref:
             return None
         element_type = field.field_type.element_type
@@ -1245,6 +1337,11 @@ class JavaGenerator(BaseGenerator):
             return field.field_type.kind == PrimitiveKind.BYTES
         if isinstance(field.field_type, ListType):
             if isinstance(field.field_type.element_type, PrimitiveType):
+                if (
+                    field.field_type.element_type.kind in 
self.PRIMITIVE_LIST_MAP
+                    and not self.java_array(field)
+                ):
+                    return False
                 return (
                     field.field_type.element_type.kind in 
self.PRIMITIVE_ARRAY_MAP
                     and not field.element_optional
diff --git a/compiler/fory_compiler/generators/rust.py 
b/compiler/fory_compiler/generators/rust.py
index 27daefe9d..777fce9a5 100644
--- a/compiler/fory_compiler/generators/rust.py
+++ b/compiler/fory_compiler/generators/rust.py
@@ -203,8 +203,12 @@ class RustGenerator(BaseGenerator):
         uses.add("use std::sync::OnceLock")
 
         for message in self.schema.messages:
+            if self.is_imported_type(message):
+                continue
             self.collect_message_uses(message, uses)
         for union in self.schema.unions:
+            if self.is_imported_type(union):
+                continue
             self.collect_union_uses(union, uses)
 
         # License header
@@ -359,6 +363,8 @@ class RustGenerator(BaseGenerator):
         has_any = any(
             self.field_type_has_any(field.field_type) for field in union.fields
         )
+        if self.to_pascal_case(union.name) != union.name:
+            lines.append("#[allow(non_camel_case_types)]")
         derives = ["ForyObject", "Debug"]
         if not has_any:
             derives.extend(["Clone", "PartialEq"])
diff --git a/cpp/fory/serialization/unsigned_serializer.h 
b/cpp/fory/serialization/unsigned_serializer.h
index 809e0136b..b6961b55e 100644
--- a/cpp/fory/serialization/unsigned_serializer.h
+++ b/cpp/fory/serialization/unsigned_serializer.h
@@ -25,6 +25,7 @@
 #include "fory/util/error.h"
 #include <array>
 #include <cstdint>
+#include <limits>
 #include <vector>
 
 namespace fory {
@@ -753,17 +754,22 @@ template <> struct Serializer<std::vector<uint16_t>> {
 
   static inline void write_data(const std::vector<uint16_t> &vec,
                                 WriteContext &ctx) {
+    uint64_t total_bytes = static_cast<uint64_t>(vec.size()) * 
sizeof(uint16_t);
+    if (total_bytes > std::numeric_limits<uint32_t>::max()) {
+      ctx.set_error(Error::invalid("Vector byte size exceeds uint32_t range"));
+      return;
+    }
     Buffer &buffer = ctx.buffer();
-    size_t data_size = vec.size() * sizeof(uint16_t);
-    size_t max_size = 8 + data_size;
+    size_t max_size = 8 + static_cast<size_t>(total_bytes);
     buffer.grow(static_cast<uint32_t>(max_size));
     uint32_t writer_index = buffer.writer_index();
     writer_index +=
-        buffer.put_var_uint32(writer_index, static_cast<uint32_t>(vec.size()));
-    if (!vec.empty()) {
-      buffer.unsafe_put(writer_index, vec.data(), data_size);
+        buffer.put_var_uint32(writer_index, 
static_cast<uint32_t>(total_bytes));
+    if (total_bytes > 0) {
+      buffer.unsafe_put(writer_index, vec.data(),
+                        static_cast<uint32_t>(total_bytes));
     }
-    buffer.writer_index(writer_index + static_cast<uint32_t>(data_size));
+    buffer.writer_index(writer_index + static_cast<uint32_t>(total_bytes));
   }
 
   static inline void write_data_generic(const std::vector<uint16_t> &vec,
@@ -788,16 +794,24 @@ template <> struct Serializer<std::vector<uint16_t>> {
   }
 
   static inline std::vector<uint16_t> read_data(ReadContext &ctx) {
-    uint32_t length = ctx.read_var_uint32(ctx.error());
-    if (FORY_PREDICT_FALSE(length * sizeof(uint16_t) >
-                           ctx.buffer().remaining_size())) {
-      ctx.set_error(
-          Error::invalid_data("Invalid length: " + std::to_string(length)));
+    uint32_t total_bytes = ctx.read_var_uint32(ctx.error());
+    if (FORY_PREDICT_FALSE(ctx.has_error())) {
+      return std::vector<uint16_t>();
+    }
+    if (total_bytes % sizeof(uint16_t) != 0) {
+      ctx.set_error(Error::invalid_data("Invalid length: " +
+                                        std::to_string(total_bytes)));
       return std::vector<uint16_t>();
     }
+    if (FORY_PREDICT_FALSE(total_bytes > ctx.buffer().remaining_size())) {
+      ctx.set_error(Error::invalid_data("Invalid length: " +
+                                        std::to_string(total_bytes)));
+      return std::vector<uint16_t>();
+    }
+    size_t length = total_bytes / sizeof(uint16_t);
     std::vector<uint16_t> vec(length);
-    if (length > 0) {
-      ctx.read_bytes(vec.data(), length * sizeof(uint16_t), ctx.error());
+    if (total_bytes > 0) {
+      ctx.read_bytes(vec.data(), total_bytes, ctx.error());
     }
     return vec;
   }
@@ -842,17 +856,22 @@ template <> struct Serializer<std::vector<uint32_t>> {
 
   static inline void write_data(const std::vector<uint32_t> &vec,
                                 WriteContext &ctx) {
+    uint64_t total_bytes = static_cast<uint64_t>(vec.size()) * 
sizeof(uint32_t);
+    if (total_bytes > std::numeric_limits<uint32_t>::max()) {
+      ctx.set_error(Error::invalid("Vector byte size exceeds uint32_t range"));
+      return;
+    }
     Buffer &buffer = ctx.buffer();
-    size_t data_size = vec.size() * sizeof(uint32_t);
-    size_t max_size = 8 + data_size;
+    size_t max_size = 8 + static_cast<size_t>(total_bytes);
     buffer.grow(static_cast<uint32_t>(max_size));
     uint32_t writer_index = buffer.writer_index();
     writer_index +=
-        buffer.put_var_uint32(writer_index, static_cast<uint32_t>(vec.size()));
-    if (!vec.empty()) {
-      buffer.unsafe_put(writer_index, vec.data(), data_size);
+        buffer.put_var_uint32(writer_index, 
static_cast<uint32_t>(total_bytes));
+    if (total_bytes > 0) {
+      buffer.unsafe_put(writer_index, vec.data(),
+                        static_cast<uint32_t>(total_bytes));
     }
-    buffer.writer_index(writer_index + static_cast<uint32_t>(data_size));
+    buffer.writer_index(writer_index + static_cast<uint32_t>(total_bytes));
   }
 
   static inline void write_data_generic(const std::vector<uint32_t> &vec,
@@ -877,16 +896,24 @@ template <> struct Serializer<std::vector<uint32_t>> {
   }
 
   static inline std::vector<uint32_t> read_data(ReadContext &ctx) {
-    uint32_t length = ctx.read_var_uint32(ctx.error());
-    if (FORY_PREDICT_FALSE(length * sizeof(uint32_t) >
-                           ctx.buffer().remaining_size())) {
-      ctx.set_error(
-          Error::invalid_data("Invalid length: " + std::to_string(length)));
+    uint32_t total_bytes = ctx.read_var_uint32(ctx.error());
+    if (FORY_PREDICT_FALSE(ctx.has_error())) {
       return std::vector<uint32_t>();
     }
+    if (total_bytes % sizeof(uint32_t) != 0) {
+      ctx.set_error(Error::invalid_data("Invalid length: " +
+                                        std::to_string(total_bytes)));
+      return std::vector<uint32_t>();
+    }
+    if (FORY_PREDICT_FALSE(total_bytes > ctx.buffer().remaining_size())) {
+      ctx.set_error(Error::invalid_data("Invalid length: " +
+                                        std::to_string(total_bytes)));
+      return std::vector<uint32_t>();
+    }
+    size_t length = total_bytes / sizeof(uint32_t);
     std::vector<uint32_t> vec(length);
-    if (length > 0) {
-      ctx.read_bytes(vec.data(), length * sizeof(uint32_t), ctx.error());
+    if (total_bytes > 0) {
+      ctx.read_bytes(vec.data(), total_bytes, ctx.error());
     }
     return vec;
   }
@@ -931,17 +958,22 @@ template <> struct Serializer<std::vector<uint64_t>> {
 
   static inline void write_data(const std::vector<uint64_t> &vec,
                                 WriteContext &ctx) {
+    uint64_t total_bytes = static_cast<uint64_t>(vec.size()) * 
sizeof(uint64_t);
+    if (total_bytes > std::numeric_limits<uint32_t>::max()) {
+      ctx.set_error(Error::invalid("Vector byte size exceeds uint32_t range"));
+      return;
+    }
     Buffer &buffer = ctx.buffer();
-    size_t data_size = vec.size() * sizeof(uint64_t);
-    size_t max_size = 8 + data_size;
+    size_t max_size = 8 + static_cast<size_t>(total_bytes);
     buffer.grow(static_cast<uint32_t>(max_size));
     uint32_t writer_index = buffer.writer_index();
     writer_index +=
-        buffer.put_var_uint32(writer_index, static_cast<uint32_t>(vec.size()));
-    if (!vec.empty()) {
-      buffer.unsafe_put(writer_index, vec.data(), data_size);
+        buffer.put_var_uint32(writer_index, 
static_cast<uint32_t>(total_bytes));
+    if (total_bytes > 0) {
+      buffer.unsafe_put(writer_index, vec.data(),
+                        static_cast<uint32_t>(total_bytes));
     }
-    buffer.writer_index(writer_index + static_cast<uint32_t>(data_size));
+    buffer.writer_index(writer_index + static_cast<uint32_t>(total_bytes));
   }
 
   static inline void write_data_generic(const std::vector<uint64_t> &vec,
@@ -966,16 +998,24 @@ template <> struct Serializer<std::vector<uint64_t>> {
   }
 
   static inline std::vector<uint64_t> read_data(ReadContext &ctx) {
-    uint32_t length = ctx.read_var_uint32(ctx.error());
-    if (FORY_PREDICT_FALSE(length * sizeof(uint64_t) >
-                           ctx.buffer().remaining_size())) {
-      ctx.set_error(
-          Error::invalid_data("Invalid length: " + std::to_string(length)));
+    uint32_t total_bytes = ctx.read_var_uint32(ctx.error());
+    if (FORY_PREDICT_FALSE(ctx.has_error())) {
+      return std::vector<uint64_t>();
+    }
+    if (total_bytes % sizeof(uint64_t) != 0) {
+      ctx.set_error(Error::invalid_data("Invalid length: " +
+                                        std::to_string(total_bytes)));
+      return std::vector<uint64_t>();
+    }
+    if (FORY_PREDICT_FALSE(total_bytes > ctx.buffer().remaining_size())) {
+      ctx.set_error(Error::invalid_data("Invalid length: " +
+                                        std::to_string(total_bytes)));
       return std::vector<uint64_t>();
     }
+    size_t length = total_bytes / sizeof(uint64_t);
     std::vector<uint64_t> vec(length);
-    if (length > 0) {
-      ctx.read_bytes(vec.data(), length * sizeof(uint64_t), ctx.error());
+    if (total_bytes > 0) {
+      ctx.read_bytes(vec.data(), total_bytes, ctx.error());
     }
     return vec;
   }
diff --git a/go/fory/reader.go b/go/fory/reader.go
index dd9a837bb..e8fd1a863 100644
--- a/go/fory/reader.go
+++ b/go/fory/reader.go
@@ -325,6 +325,48 @@ func (c *ReadContext) ReadInt64Slice(refMode RefMode, 
readType bool) []int64 {
        return ReadInt64Slice(c.buffer, err)
 }
 
+// ReadUint16Slice reads []uint16 with optional ref/type info
+func (c *ReadContext) ReadUint16Slice(refMode RefMode, readType bool) []uint16 
{
+       err := c.Err()
+       if refMode != RefModeNone {
+               if c.buffer.ReadInt8(err) == NullFlag {
+                       return nil
+               }
+       }
+       if readType {
+               _ = c.buffer.ReadVarUint32Small7(err)
+       }
+       return ReadUint16Slice(c.buffer, err)
+}
+
+// ReadUint32Slice reads []uint32 with optional ref/type info
+func (c *ReadContext) ReadUint32Slice(refMode RefMode, readType bool) []uint32 
{
+       err := c.Err()
+       if refMode != RefModeNone {
+               if c.buffer.ReadInt8(err) == NullFlag {
+                       return nil
+               }
+       }
+       if readType {
+               _ = c.buffer.ReadVarUint32Small7(err)
+       }
+       return ReadUint32Slice(c.buffer, err)
+}
+
+// ReadUint64Slice reads []uint64 with optional ref/type info
+func (c *ReadContext) ReadUint64Slice(refMode RefMode, readType bool) []uint64 
{
+       err := c.Err()
+       if refMode != RefModeNone {
+               if c.buffer.ReadInt8(err) == NullFlag {
+                       return nil
+               }
+       }
+       if readType {
+               _ = c.buffer.ReadVarUint32Small7(err)
+       }
+       return ReadUint64Slice(c.buffer, err)
+}
+
 // ReadIntSlice reads []int with optional ref/type info
 func (c *ReadContext) ReadIntSlice(refMode RefMode, readType bool) []int {
        err := c.Err()
diff --git a/go/fory/slice_primitive.go b/go/fory/slice_primitive.go
index cf83ab76b..0b6c7dc05 100644
--- a/go/fory/slice_primitive.go
+++ b/go/fory/slice_primitive.go
@@ -59,8 +59,8 @@ func (s byteSliceSerializer) Read(ctx *ReadContext, refMode 
RefMode, readType bo
        if done || ctx.HasError() {
                return
        }
-       if readType && typeId != uint32(BINARY) {
-               ctx.SetError(DeserializationErrorf("slice type mismatch: 
expected BINARY (%d), got %d", BINARY, typeId))
+       if readType && typeId != uint32(BINARY) && typeId != 
uint32(UINT8_ARRAY) {
+               ctx.SetError(DeserializationErrorf("slice type mismatch: 
expected BINARY (%d) or UINT8_ARRAY (%d), got %d", BINARY, UINT8_ARRAY, typeId))
                return
        }
        s.ReadData(ctx, value)
@@ -291,6 +291,120 @@ func (s int64SliceSerializer) ReadData(ctx *ReadContext, 
value reflect.Value) {
        *(*[]int64)(value.Addr().UnsafePointer()) = 
ReadInt64Slice(ctx.Buffer(), ctx.Err())
 }
 
+// ============================================================================
+// uint16SliceSerializer - optimized []uint16 serialization
+// ============================================================================
+
+type uint16SliceSerializer struct{}
+
+func (s uint16SliceSerializer) WriteData(ctx *WriteContext, value 
reflect.Value) {
+       WriteUint16Slice(ctx.Buffer(), value.Interface().([]uint16))
+}
+
+func (s uint16SliceSerializer) Write(ctx *WriteContext, refMode RefMode, 
writeType bool, hasGenerics bool, value reflect.Value) {
+       done := writeSliceRefAndType(ctx, refMode, writeType, value, 
UINT16_ARRAY)
+       if done || ctx.HasError() {
+               return
+       }
+       s.WriteData(ctx, value)
+}
+
+func (s uint16SliceSerializer) Read(ctx *ReadContext, refMode RefMode, 
readType bool, hasGenerics bool, value reflect.Value) {
+       done, typeId := readSliceRefAndType(ctx, refMode, readType, value)
+       if done || ctx.HasError() {
+               return
+       }
+       if readType && typeId != uint32(UINT16_ARRAY) {
+               ctx.SetError(DeserializationErrorf("slice type mismatch: 
expected UINT16_ARRAY (%d), got %d", UINT16_ARRAY, typeId))
+               return
+       }
+       s.ReadData(ctx, value)
+}
+
+func (s uint16SliceSerializer) ReadWithTypeInfo(ctx *ReadContext, refMode 
RefMode, typeInfo *TypeInfo, value reflect.Value) {
+       s.Read(ctx, refMode, false, false, value)
+}
+
+func (s uint16SliceSerializer) ReadData(ctx *ReadContext, value reflect.Value) 
{
+       *(*[]uint16)(value.Addr().UnsafePointer()) = 
ReadUint16Slice(ctx.Buffer(), ctx.Err())
+}
+
+// ============================================================================
+// uint32SliceSerializer - optimized []uint32 serialization
+// ============================================================================
+
+type uint32SliceSerializer struct{}
+
+func (s uint32SliceSerializer) WriteData(ctx *WriteContext, value 
reflect.Value) {
+       WriteUint32Slice(ctx.Buffer(), value.Interface().([]uint32))
+}
+
+func (s uint32SliceSerializer) Write(ctx *WriteContext, refMode RefMode, 
writeType bool, hasGenerics bool, value reflect.Value) {
+       done := writeSliceRefAndType(ctx, refMode, writeType, value, 
UINT32_ARRAY)
+       if done || ctx.HasError() {
+               return
+       }
+       s.WriteData(ctx, value)
+}
+
+func (s uint32SliceSerializer) Read(ctx *ReadContext, refMode RefMode, 
readType bool, hasGenerics bool, value reflect.Value) {
+       done, typeId := readSliceRefAndType(ctx, refMode, readType, value)
+       if done || ctx.HasError() {
+               return
+       }
+       if readType && typeId != uint32(UINT32_ARRAY) {
+               ctx.SetError(DeserializationErrorf("slice type mismatch: 
expected UINT32_ARRAY (%d), got %d", UINT32_ARRAY, typeId))
+               return
+       }
+       s.ReadData(ctx, value)
+}
+
+func (s uint32SliceSerializer) ReadWithTypeInfo(ctx *ReadContext, refMode 
RefMode, typeInfo *TypeInfo, value reflect.Value) {
+       s.Read(ctx, refMode, false, false, value)
+}
+
+func (s uint32SliceSerializer) ReadData(ctx *ReadContext, value reflect.Value) 
{
+       *(*[]uint32)(value.Addr().UnsafePointer()) = 
ReadUint32Slice(ctx.Buffer(), ctx.Err())
+}
+
+// ============================================================================
+// uint64SliceSerializer - optimized []uint64 serialization
+// ============================================================================
+
+type uint64SliceSerializer struct{}
+
+func (s uint64SliceSerializer) WriteData(ctx *WriteContext, value 
reflect.Value) {
+       WriteUint64Slice(ctx.Buffer(), value.Interface().([]uint64))
+}
+
+func (s uint64SliceSerializer) Write(ctx *WriteContext, refMode RefMode, 
writeType bool, hasGenerics bool, value reflect.Value) {
+       done := writeSliceRefAndType(ctx, refMode, writeType, value, 
UINT64_ARRAY)
+       if done || ctx.HasError() {
+               return
+       }
+       s.WriteData(ctx, value)
+}
+
+func (s uint64SliceSerializer) Read(ctx *ReadContext, refMode RefMode, 
readType bool, hasGenerics bool, value reflect.Value) {
+       done, typeId := readSliceRefAndType(ctx, refMode, readType, value)
+       if done || ctx.HasError() {
+               return
+       }
+       if readType && typeId != uint32(UINT64_ARRAY) {
+               ctx.SetError(DeserializationErrorf("slice type mismatch: 
expected UINT64_ARRAY (%d), got %d", UINT64_ARRAY, typeId))
+               return
+       }
+       s.ReadData(ctx, value)
+}
+
+func (s uint64SliceSerializer) ReadWithTypeInfo(ctx *ReadContext, refMode 
RefMode, typeInfo *TypeInfo, value reflect.Value) {
+       s.Read(ctx, refMode, false, false, value)
+}
+
+func (s uint64SliceSerializer) ReadData(ctx *ReadContext, value reflect.Value) 
{
+       *(*[]uint64)(value.Addr().UnsafePointer()) = 
ReadUint64Slice(ctx.Buffer(), ctx.Err())
+}
+
 // ============================================================================
 // float32SliceSerializer - optimized []float32 serialization
 // ============================================================================
@@ -754,6 +868,120 @@ func ReadInt64Slice(buf *ByteBuffer, err *Error) []int64 {
        return result
 }
 
+// WriteUint16Slice writes []uint16 to buffer using ARRAY protocol
+//
+//go:inline
+func WriteUint16Slice(buf *ByteBuffer, value []uint16) {
+       size := len(value) * 2
+       buf.WriteLength(size)
+       if len(value) > 0 {
+               if isLittleEndian {
+                       
buf.WriteBinary(unsafe.Slice((*byte)(unsafe.Pointer(&value[0])), size))
+               } else {
+                       for i := 0; i < len(value); i++ {
+                               buf.WriteInt16(int16(value[i]))
+                       }
+               }
+       }
+}
+
+// ReadUint16Slice reads []uint16 from buffer using ARRAY protocol
+//
+//go:inline
+func ReadUint16Slice(buf *ByteBuffer, err *Error) []uint16 {
+       size := buf.ReadLength(err)
+       length := size / 2
+       if length == 0 {
+               return make([]uint16, 0)
+       }
+       result := make([]uint16, length)
+       if isLittleEndian {
+               raw := buf.ReadBinary(size, err)
+               copy(unsafe.Slice((*byte)(unsafe.Pointer(&result[0])), size), 
raw)
+       } else {
+               for i := 0; i < length; i++ {
+                       result[i] = uint16(buf.ReadInt16(err))
+               }
+       }
+       return result
+}
+
+// WriteUint32Slice writes []uint32 to buffer using ARRAY protocol
+//
+//go:inline
+func WriteUint32Slice(buf *ByteBuffer, value []uint32) {
+       size := len(value) * 4
+       buf.WriteLength(size)
+       if len(value) > 0 {
+               if isLittleEndian {
+                       
buf.WriteBinary(unsafe.Slice((*byte)(unsafe.Pointer(&value[0])), size))
+               } else {
+                       for i := 0; i < len(value); i++ {
+                               buf.WriteInt32(int32(value[i]))
+                       }
+               }
+       }
+}
+
+// ReadUint32Slice reads []uint32 from buffer using ARRAY protocol
+//
+//go:inline
+func ReadUint32Slice(buf *ByteBuffer, err *Error) []uint32 {
+       size := buf.ReadLength(err)
+       length := size / 4
+       if length == 0 {
+               return make([]uint32, 0)
+       }
+       result := make([]uint32, length)
+       if isLittleEndian {
+               raw := buf.ReadBinary(size, err)
+               copy(unsafe.Slice((*byte)(unsafe.Pointer(&result[0])), size), 
raw)
+       } else {
+               for i := 0; i < length; i++ {
+                       result[i] = uint32(buf.ReadInt32(err))
+               }
+       }
+       return result
+}
+
+// WriteUint64Slice writes []uint64 to buffer using ARRAY protocol
+//
+//go:inline
+func WriteUint64Slice(buf *ByteBuffer, value []uint64) {
+       size := len(value) * 8
+       buf.WriteLength(size)
+       if len(value) > 0 {
+               if isLittleEndian {
+                       
buf.WriteBinary(unsafe.Slice((*byte)(unsafe.Pointer(&value[0])), size))
+               } else {
+                       for i := 0; i < len(value); i++ {
+                               buf.WriteInt64(int64(value[i]))
+                       }
+               }
+       }
+}
+
+// ReadUint64Slice reads []uint64 from buffer using ARRAY protocol
+//
+//go:inline
+func ReadUint64Slice(buf *ByteBuffer, err *Error) []uint64 {
+       size := buf.ReadLength(err)
+       length := size / 8
+       if length == 0 {
+               return make([]uint64, 0)
+       }
+       result := make([]uint64, length)
+       if isLittleEndian {
+               raw := buf.ReadBinary(size, err)
+               copy(unsafe.Slice((*byte)(unsafe.Pointer(&result[0])), size), 
raw)
+       } else {
+               for i := 0; i < length; i++ {
+                       result[i] = uint64(buf.ReadInt64(err))
+               }
+       }
+       return result
+}
+
 // WriteFloat32Slice writes []float32 to buffer using ARRAY protocol
 //
 //go:inline
diff --git a/go/fory/struct.go b/go/fory/struct.go
index ff4aaece9..53b81f0a5 100644
--- a/go/fory/struct.go
+++ b/go/fory/struct.go
@@ -1590,6 +1590,24 @@ func (s *structSerializer) writeRemainingField(ctx 
*WriteContext, ptr unsafe.Poi
                        }
                        ctx.WriteInt64Slice(*(*[]int64)(fieldPtr), 
field.RefMode, false)
                        return
+               case Uint16SliceDispatchId:
+                       if field.RefMode == RefModeTracking {
+                               break
+                       }
+                       ctx.WriteUint16Slice(*(*[]uint16)(fieldPtr), 
field.RefMode, false)
+                       return
+               case Uint32SliceDispatchId:
+                       if field.RefMode == RefModeTracking {
+                               break
+                       }
+                       ctx.WriteUint32Slice(*(*[]uint32)(fieldPtr), 
field.RefMode, false)
+                       return
+               case Uint64SliceDispatchId:
+                       if field.RefMode == RefModeTracking {
+                               break
+                       }
+                       ctx.WriteUint64Slice(*(*[]uint64)(fieldPtr), 
field.RefMode, false)
+                       return
                case IntSliceDispatchId:
                        if field.RefMode == RefModeTracking {
                                break
@@ -2769,6 +2787,24 @@ func (s *structSerializer) readRemainingField(ctx 
*ReadContext, ptr unsafe.Point
                        }
                        *(*[]int64)(fieldPtr) = 
ctx.ReadInt64Slice(field.RefMode, false)
                        return
+               case Uint16SliceDispatchId:
+                       if field.RefMode == RefModeTracking {
+                               break
+                       }
+                       *(*[]uint16)(fieldPtr) = 
ctx.ReadUint16Slice(field.RefMode, false)
+                       return
+               case Uint32SliceDispatchId:
+                       if field.RefMode == RefModeTracking {
+                               break
+                       }
+                       *(*[]uint32)(fieldPtr) = 
ctx.ReadUint32Slice(field.RefMode, false)
+                       return
+               case Uint64SliceDispatchId:
+                       if field.RefMode == RefModeTracking {
+                               break
+                       }
+                       *(*[]uint64)(fieldPtr) = 
ctx.ReadUint64Slice(field.RefMode, false)
+                       return
                case IntSliceDispatchId:
                        if field.RefMode == RefModeTracking {
                                break
diff --git a/go/fory/type_resolver.go b/go/fory/type_resolver.go
index 0069dfc0d..971fb5627 100644
--- a/go/fory/type_resolver.go
+++ b/go/fory/type_resolver.go
@@ -67,6 +67,9 @@ var (
        int64SliceType       = reflect.TypeOf((*[]int64)(nil)).Elem()
        intSliceType         = reflect.TypeOf((*[]int)(nil)).Elem()
        uintSliceType        = reflect.TypeOf((*[]uint)(nil)).Elem()
+       uint16SliceType      = reflect.TypeOf((*[]uint16)(nil)).Elem()
+       uint32SliceType      = reflect.TypeOf((*[]uint32)(nil)).Elem()
+       uint64SliceType      = reflect.TypeOf((*[]uint64)(nil)).Elem()
        float32SliceType     = reflect.TypeOf((*[]float32)(nil)).Elem()
        float64SliceType     = reflect.TypeOf((*[]float64)(nil)).Elem()
        float16SliceType     = reflect.TypeOf((*[]float16.Float16)(nil)).Elem()
@@ -398,6 +401,9 @@ func (r *TypeResolver) initialize() {
                {int64SliceType, INT64_ARRAY, int64SliceSerializer{}},
                {intSliceType, INT64_ARRAY, intSliceSerializer{}}, // int is 
typically 64-bit
                {uintSliceType, INT64_ARRAY, uintSliceSerializer{}},
+               {uint16SliceType, UINT16_ARRAY, uint16SliceSerializer{}},
+               {uint32SliceType, UINT32_ARRAY, uint32SliceSerializer{}},
+               {uint64SliceType, UINT64_ARRAY, uint64SliceSerializer{}},
                {float32SliceType, FLOAT32_ARRAY, float32SliceSerializer{}},
                {float64SliceType, FLOAT64_ARRAY, float64SliceSerializer{}},
                {float16SliceType, FLOAT16_ARRAY, float16SliceSerializer{}},
@@ -444,6 +450,8 @@ func (r *TypeResolver) initialize() {
                typeId TypeId
                goType reflect.Type
        }{
+               // Byte slice can be encoded as BINARY or UINT8_ARRAY
+               {UINT8_ARRAY, byteSliceType},
                // Fixed-size integer encodings (in addition to varint defaults)
                {UINT32, uint32Type},        // Fixed UINT32 (11) → uint32
                {UINT64, uint64Type},        // Fixed UINT64 (13) → uint64
diff --git a/go/fory/types.go b/go/fory/types.go
index 5227cdbad..b72d27db5 100644
--- a/go/fory/types.go
+++ b/go/fory/types.go
@@ -353,6 +353,9 @@ const (
        Int64SliceDispatchId
        IntSliceDispatchId
        UintSliceDispatchId
+       Uint16SliceDispatchId
+       Uint32SliceDispatchId
+       Uint64SliceDispatchId
        Float32SliceDispatchId
        Float64SliceDispatchId
        Float16SliceDispatchId
@@ -432,19 +435,20 @@ func GetDispatchId(t reflect.Type) DispatchId {
                        return IntSliceDispatchId
                case reflect.Uint:
                        return UintSliceDispatchId
-               case reflect.Float32:
-                       return Float32SliceDispatchId
-               case reflect.Float64:
-                       return Float64SliceDispatchId
                case reflect.Uint16:
                        // Check if it's float16 slice
                        if t.Elem().Name() == "Float16" && (t.Elem().PkgPath() 
== "github.com/apache/fory/go/fory/float16" || 
strings.HasSuffix(t.Elem().PkgPath(), "/float16")) {
                                return Float16SliceDispatchId
                        }
-                       // Use Int16SliceDispatchId for Uint16 as they share 
the same 2-byte size
-                       // and serialization logic in many cases, or it falls 
back to generic if needed.
-                       return Int16SliceDispatchId
-
+                       return Uint16SliceDispatchId
+               case reflect.Uint32:
+                       return Uint32SliceDispatchId
+               case reflect.Uint64:
+                       return Uint64SliceDispatchId
+               case reflect.Float32:
+                       return Float32SliceDispatchId
+               case reflect.Float64:
+                       return Float64SliceDispatchId
                case reflect.Bool:
                        return BoolSliceDispatchId
                case reflect.String:
diff --git a/go/fory/writer.go b/go/fory/writer.go
index 27907a587..47849e93a 100644
--- a/go/fory/writer.go
+++ b/go/fory/writer.go
@@ -307,6 +307,51 @@ func (c *WriteContext) WriteInt64Slice(value []int64, 
refMode RefMode, writeType
        WriteInt64Slice(c.buffer, value)
 }
 
+// WriteUint16Slice writes []uint16 with ref/type info
+func (c *WriteContext) WriteUint16Slice(value []uint16, refMode RefMode, 
writeTypeInfo bool) {
+       if refMode != RefModeNone {
+               if value == nil {
+                       c.buffer.WriteInt8(NullFlag)
+                       return
+               }
+               c.buffer.WriteInt8(NotNullValueFlag)
+       }
+       if writeTypeInfo {
+               c.WriteTypeId(UINT16_ARRAY)
+       }
+       WriteUint16Slice(c.buffer, value)
+}
+
+// WriteUint32Slice writes []uint32 with ref/type info
+func (c *WriteContext) WriteUint32Slice(value []uint32, refMode RefMode, 
writeTypeInfo bool) {
+       if refMode != RefModeNone {
+               if value == nil {
+                       c.buffer.WriteInt8(NullFlag)
+                       return
+               }
+               c.buffer.WriteInt8(NotNullValueFlag)
+       }
+       if writeTypeInfo {
+               c.WriteTypeId(UINT32_ARRAY)
+       }
+       WriteUint32Slice(c.buffer, value)
+}
+
+// WriteUint64Slice writes []uint64 with ref/type info
+func (c *WriteContext) WriteUint64Slice(value []uint64, refMode RefMode, 
writeTypeInfo bool) {
+       if refMode != RefModeNone {
+               if value == nil {
+                       c.buffer.WriteInt8(NullFlag)
+                       return
+               }
+               c.buffer.WriteInt8(NotNullValueFlag)
+       }
+       if writeTypeInfo {
+               c.WriteTypeId(UINT64_ARRAY)
+       }
+       WriteUint64Slice(c.buffer, value)
+}
+
 // WriteIntSlice writes []int with ref/type info
 func (c *WriteContext) WriteIntSlice(value []int, refMode RefMode, 
writeTypeInfo bool) {
        if refMode != RefModeNone {
diff --git a/integration_tests/idl_tests/cpp/main.cc 
b/integration_tests/idl_tests/cpp/main.cc
index d8ef4ead5..a429bb332 100644
--- a/integration_tests/idl_tests/cpp/main.cc
+++ b/integration_tests/idl_tests/cpp/main.cc
@@ -30,6 +30,7 @@
 
 #include "addressbook.h"
 #include "any_example.h"
+#include "collection.h"
 #include "complex_fbs.h"
 #include "complex_pb.h"
 #include "fory/serialization/any_serializer.h"
@@ -171,6 +172,7 @@ fory::Result<void, fory::Error> RunRoundTrip(bool 
compatible) {
   addressbook::register_types(fory);
   monster::register_types(fory);
   complex_fbs::register_types(fory);
+  collection::register_types(fory);
   optional_types::register_types(fory);
   any_example::register_types(fory);
 
@@ -310,6 +312,86 @@ fory::Result<void, fory::Error> RunRoundTrip(bool 
compatible) {
         fory::Error::invalid("primitive types roundtrip mismatch"));
   }
 
+  collection::NumericCollections collections;
+  *collections.mutable_int8_values() = {
+      static_cast<int8_t>(1), static_cast<int8_t>(-2), static_cast<int8_t>(3)};
+  *collections.mutable_int16_values() = {static_cast<int16_t>(100),
+                                         static_cast<int16_t>(-200),
+                                         static_cast<int16_t>(300)};
+  *collections.mutable_int32_values() = {1000, -2000, 3000};
+  *collections.mutable_int64_values() = {10000, -20000, 30000};
+  *collections.mutable_uint8_values() = {static_cast<uint8_t>(200),
+                                         static_cast<uint8_t>(250)};
+  *collections.mutable_uint16_values() = {static_cast<uint16_t>(50000),
+                                          static_cast<uint16_t>(60000)};
+  *collections.mutable_uint32_values() = {2000000000U, 2100000000U};
+  *collections.mutable_uint64_values() = {9000000000ULL, 12000000000ULL};
+  *collections.mutable_float32_values() = {1.5F, 2.5F};
+  *collections.mutable_float64_values() = {3.5, 4.5};
+
+  collection::NumericCollectionUnion collection_union =
+      collection::NumericCollectionUnion::int32_values(
+          std::vector<int32_t>{7, 8, 9});
+
+  collection::NumericCollectionsArray collections_array;
+  *collections_array.mutable_int8_values() = {
+      static_cast<int8_t>(1), static_cast<int8_t>(-2), static_cast<int8_t>(3)};
+  *collections_array.mutable_int16_values() = {static_cast<int16_t>(100),
+                                               static_cast<int16_t>(-200),
+                                               static_cast<int16_t>(300)};
+  *collections_array.mutable_int32_values() = {1000, -2000, 3000};
+  *collections_array.mutable_int64_values() = {10000, -20000, 30000};
+  *collections_array.mutable_uint8_values() = {static_cast<uint8_t>(200),
+                                               static_cast<uint8_t>(250)};
+  *collections_array.mutable_uint16_values() = {static_cast<uint16_t>(50000),
+                                                static_cast<uint16_t>(60000)};
+  *collections_array.mutable_uint32_values() = {2000000000U, 2100000000U};
+  *collections_array.mutable_uint64_values() = {9000000000ULL, 12000000000ULL};
+  *collections_array.mutable_float32_values() = {1.5F, 2.5F};
+  *collections_array.mutable_float64_values() = {3.5, 4.5};
+
+  collection::NumericCollectionArrayUnion collection_array_union =
+      collection::NumericCollectionArrayUnion::uint16_values(
+          std::vector<uint16_t>{1000, 2000, 3000});
+
+  FORY_TRY(collection_bytes, fory.serialize(collections));
+  FORY_TRY(collection_roundtrip,
+           fory.deserialize<collection::NumericCollections>(
+               collection_bytes.data(), collection_bytes.size()));
+  if (!(collection_roundtrip == collections)) {
+    return fory::Unexpected(
+        fory::Error::invalid("collection roundtrip mismatch"));
+  }
+
+  FORY_TRY(collection_union_bytes, fory.serialize(collection_union));
+  FORY_TRY(collection_union_roundtrip,
+           fory.deserialize<collection::NumericCollectionUnion>(
+               collection_union_bytes.data(), collection_union_bytes.size()));
+  if (!(collection_union_roundtrip == collection_union)) {
+    return fory::Unexpected(
+        fory::Error::invalid("collection union roundtrip mismatch"));
+  }
+
+  FORY_TRY(collection_array_bytes, fory.serialize(collections_array));
+  FORY_TRY(collection_array_roundtrip,
+           fory.deserialize<collection::NumericCollectionsArray>(
+               collection_array_bytes.data(), collection_array_bytes.size()));
+  if (!(collection_array_roundtrip == collections_array)) {
+    return fory::Unexpected(
+        fory::Error::invalid("collection array roundtrip mismatch"));
+  }
+
+  FORY_TRY(collection_array_union_bytes,
+           fory.serialize(collection_array_union));
+  FORY_TRY(collection_array_union_roundtrip,
+           fory.deserialize<collection::NumericCollectionArrayUnion>(
+               collection_array_union_bytes.data(),
+               collection_array_union_bytes.size()));
+  if (!(collection_array_union_roundtrip == collection_array_union)) {
+    return fory::Unexpected(
+        fory::Error::invalid("collection array union roundtrip mismatch"));
+  }
+
   monster::Vec3 pos;
   pos.set_x(1.0F);
   pos.set_y(2.0F);
@@ -468,6 +550,61 @@ fory::Result<void, fory::Error> RunRoundTrip(bool 
compatible) {
     FORY_RETURN_IF_ERROR(WriteFile(primitive_file, peer_bytes));
   }
 
+  const char *collection_file = std::getenv("DATA_FILE_COLLECTION");
+  if (collection_file != nullptr && collection_file[0] != '\0') {
+    FORY_TRY(payload, ReadFile(collection_file));
+    FORY_TRY(peer_collections, 
fory.deserialize<collection::NumericCollections>(
+                                   payload.data(), payload.size()));
+    if (!(peer_collections == collections)) {
+      return fory::Unexpected(
+          fory::Error::invalid("peer collection payload mismatch"));
+    }
+    FORY_TRY(peer_bytes, fory.serialize(peer_collections));
+    FORY_RETURN_IF_ERROR(WriteFile(collection_file, peer_bytes));
+  }
+
+  const char *collection_union_file = 
std::getenv("DATA_FILE_COLLECTION_UNION");
+  if (collection_union_file != nullptr && collection_union_file[0] != '\0') {
+    FORY_TRY(payload, ReadFile(collection_union_file));
+    FORY_TRY(peer_union, fory.deserialize<collection::NumericCollectionUnion>(
+                             payload.data(), payload.size()));
+    if (!(peer_union == collection_union)) {
+      return fory::Unexpected(
+          fory::Error::invalid("peer collection union payload mismatch"));
+    }
+    FORY_TRY(peer_bytes, fory.serialize(peer_union));
+    FORY_RETURN_IF_ERROR(WriteFile(collection_union_file, peer_bytes));
+  }
+
+  const char *collection_array_file = 
std::getenv("DATA_FILE_COLLECTION_ARRAY");
+  if (collection_array_file != nullptr && collection_array_file[0] != '\0') {
+    FORY_TRY(payload, ReadFile(collection_array_file));
+    FORY_TRY(peer_array, fory.deserialize<collection::NumericCollectionsArray>(
+                             payload.data(), payload.size()));
+    if (!(peer_array == collections_array)) {
+      return fory::Unexpected(
+          fory::Error::invalid("peer collection array payload mismatch"));
+    }
+    FORY_TRY(peer_bytes, fory.serialize(peer_array));
+    FORY_RETURN_IF_ERROR(WriteFile(collection_array_file, peer_bytes));
+  }
+
+  const char *collection_array_union_file =
+      std::getenv("DATA_FILE_COLLECTION_ARRAY_UNION");
+  if (collection_array_union_file != nullptr &&
+      collection_array_union_file[0] != '\0') {
+    FORY_TRY(payload, ReadFile(collection_array_union_file));
+    FORY_TRY(peer_array_union,
+             fory.deserialize<collection::NumericCollectionArrayUnion>(
+                 payload.data(), payload.size()));
+    if (!(peer_array_union == collection_array_union)) {
+      return fory::Unexpected(
+          fory::Error::invalid("peer collection array union payload 
mismatch"));
+    }
+    FORY_TRY(peer_bytes, fory.serialize(peer_array_union));
+    FORY_RETURN_IF_ERROR(WriteFile(collection_array_union_file, peer_bytes));
+  }
+
   const char *monster_file = std::getenv("DATA_FILE_FLATBUFFERS_MONSTER");
   if (monster_file != nullptr && monster_file[0] != '\0') {
     FORY_TRY(payload, ReadFile(monster_file));
diff --git a/integration_tests/idl_tests/generate_idl.py 
b/integration_tests/idl_tests/generate_idl.py
index c98aaec7a..d6d0da11d 100755
--- a/integration_tests/idl_tests/generate_idl.py
+++ b/integration_tests/idl_tests/generate_idl.py
@@ -26,6 +26,7 @@ REPO_ROOT = Path(__file__).resolve().parents[2]
 IDL_DIR = Path(__file__).resolve().parent
 SCHEMAS = [
     IDL_DIR / "idl" / "addressbook.fdl",
+    IDL_DIR / "idl" / "collection.fdl",
     IDL_DIR / "idl" / "optional_types.fdl",
     IDL_DIR / "idl" / "tree.fdl",
     IDL_DIR / "idl" / "graph.fdl",
@@ -46,6 +47,7 @@ LANG_OUTPUTS = {
 
 GO_OUTPUT_OVERRIDES = {
     "addressbook.fdl": IDL_DIR / "go" / "addressbook",
+    "collection.fdl": IDL_DIR / "go" / "collection",
     "monster.fbs": IDL_DIR / "go" / "monster",
     "complex_fbs.fbs": IDL_DIR / "go" / "complex_fbs",
     "optional_types.fdl": IDL_DIR / "go" / "optional_types",
diff --git a/integration_tests/idl_tests/go/idl_roundtrip_test.go 
b/integration_tests/idl_tests/go/idl_roundtrip_test.go
index abe5d31fe..f1853766a 100644
--- a/integration_tests/idl_tests/go/idl_roundtrip_test.go
+++ b/integration_tests/idl_tests/go/idl_roundtrip_test.go
@@ -27,6 +27,7 @@ import (
        "github.com/apache/fory/go/fory/optional"
        addressbook 
"github.com/apache/fory/integration_tests/idl_tests/go/addressbook"
        anyexample 
"github.com/apache/fory/integration_tests/idl_tests/go/any_example"
+       collection 
"github.com/apache/fory/integration_tests/idl_tests/go/collection"
        complexfbs 
"github.com/apache/fory/integration_tests/idl_tests/go/complex_fbs"
        complexpb 
"github.com/apache/fory/integration_tests/idl_tests/go/complex_pb"
        graphpkg "github.com/apache/fory/integration_tests/idl_tests/go/graph"
@@ -97,6 +98,9 @@ func runAddressBookRoundTrip(t *testing.T, compatible bool) {
        if err := complexfbs.RegisterTypes(f); err != nil {
                t.Fatalf("register flatbuffers types: %v", err)
        }
+       if err := collection.RegisterTypes(f); err != nil {
+               t.Fatalf("register collection types: %v", err)
+       }
        if err := optionaltypes.RegisterTypes(f); err != nil {
                t.Fatalf("register optional types: %v", err)
        }
@@ -112,6 +116,13 @@ func runAddressBookRoundTrip(t *testing.T, compatible 
bool) {
        runLocalPrimitiveRoundTrip(t, f, types)
        runFilePrimitiveRoundTrip(t, f, types)
 
+       collections := buildNumericCollections()
+       collectionUnion := buildNumericCollectionUnion()
+       collectionsArray := buildNumericCollectionsArray()
+       collectionArrayUnion := buildNumericCollectionArrayUnion()
+       runLocalCollectionRoundTrip(t, f, collections, collectionUnion, 
collectionsArray, collectionArrayUnion)
+       runFileCollectionRoundTrip(t, f, collections, collectionUnion, 
collectionsArray, collectionArrayUnion)
+
        monster := buildMonster()
        runLocalMonsterRoundTrip(t, f, monster)
        runFileMonsterRoundTrip(t, f, monster)
@@ -441,6 +452,44 @@ func buildPrimitiveTypes() complexpb.PrimitiveTypes {
        }
 }
 
+func buildNumericCollections() collection.NumericCollections {
+       return collection.NumericCollections{
+               Int8Values:    []int8{1, -2, 3},
+               Int16Values:   []int16{100, -200, 300},
+               Int32Values:   []int32{1000, -2000, 3000},
+               Int64Values:   []int64{10000, -20000, 30000},
+               Uint8Values:   []uint8{200, 250},
+               Uint16Values:  []uint16{50000, 60000},
+               Uint32Values:  []uint32{2000000000, 2100000000},
+               Uint64Values:  []uint64{9000000000, 12000000000},
+               Float32Values: []float32{1.5, 2.5},
+               Float64Values: []float64{3.5, 4.5},
+       }
+}
+
+func buildNumericCollectionUnion() collection.NumericCollectionUnion {
+       return collection.Int32ValuesNumericCollectionUnion([]int32{7, 8, 9})
+}
+
+func buildNumericCollectionsArray() collection.NumericCollectionsArray {
+       return collection.NumericCollectionsArray{
+               Int8Values:    []int8{1, -2, 3},
+               Int16Values:   []int16{100, -200, 300},
+               Int32Values:   []int32{1000, -2000, 3000},
+               Int64Values:   []int64{10000, -20000, 30000},
+               Uint8Values:   []uint8{200, 250},
+               Uint16Values:  []uint16{50000, 60000},
+               Uint32Values:  []uint32{2000000000, 2100000000},
+               Uint64Values:  []uint64{9000000000, 12000000000},
+               Float32Values: []float32{1.5, 2.5},
+               Float64Values: []float64{3.5, 4.5},
+       }
+}
+
+func buildNumericCollectionArrayUnion() collection.NumericCollectionArrayUnion 
{
+       return 
collection.Uint16ValuesNumericCollectionArrayUnion([]uint16{1000, 2000, 3000})
+}
+
 func runLocalPrimitiveRoundTrip(t *testing.T, f *fory.Fory, types 
complexpb.PrimitiveTypes) {
        data, err := f.Serialize(&types)
        if err != nil {
@@ -484,6 +533,162 @@ func runFilePrimitiveRoundTrip(t *testing.T, f 
*fory.Fory, types complexpb.Primi
        }
 }
 
+func runLocalCollectionRoundTrip(
+       t *testing.T,
+       f *fory.Fory,
+       collections collection.NumericCollections,
+       unionValue collection.NumericCollectionUnion,
+       collectionsArray collection.NumericCollectionsArray,
+       arrayUnion collection.NumericCollectionArrayUnion,
+) {
+       data, err := f.Serialize(&collections)
+       if err != nil {
+               t.Fatalf("serialize collections: %v", err)
+       }
+
+       var out collection.NumericCollections
+       if err := f.Deserialize(data, &out); err != nil {
+               t.Fatalf("deserialize collections: %v", err)
+       }
+
+       if !reflect.DeepEqual(collections, out) {
+               t.Fatalf("collection roundtrip mismatch: %#v != %#v", 
collections, out)
+       }
+
+       unionData, err := f.Serialize(&unionValue)
+       if err != nil {
+               t.Fatalf("serialize collection union: %v", err)
+       }
+       var unionOut collection.NumericCollectionUnion
+       if err := f.Deserialize(unionData, &unionOut); err != nil {
+               t.Fatalf("deserialize collection union: %v", err)
+       }
+       if !reflect.DeepEqual(unionValue, unionOut) {
+               t.Fatalf("collection union mismatch: %#v != %#v", unionValue, 
unionOut)
+       }
+
+       arrayData, err := f.Serialize(&collectionsArray)
+       if err != nil {
+               t.Fatalf("serialize collection array: %v", err)
+       }
+       var arrayOut collection.NumericCollectionsArray
+       if err := f.Deserialize(arrayData, &arrayOut); err != nil {
+               t.Fatalf("deserialize collection array: %v", err)
+       }
+       if !reflect.DeepEqual(collectionsArray, arrayOut) {
+               t.Fatalf("collection array mismatch: %#v != %#v", 
collectionsArray, arrayOut)
+       }
+
+       arrayUnionData, err := f.Serialize(&arrayUnion)
+       if err != nil {
+               t.Fatalf("serialize collection array union: %v", err)
+       }
+       var arrayUnionOut collection.NumericCollectionArrayUnion
+       if err := f.Deserialize(arrayUnionData, &arrayUnionOut); err != nil {
+               t.Fatalf("deserialize collection array union: %v", err)
+       }
+       if !reflect.DeepEqual(arrayUnion, arrayUnionOut) {
+               t.Fatalf("collection array union mismatch: %#v != %#v", 
arrayUnion, arrayUnionOut)
+       }
+}
+
+func runFileCollectionRoundTrip(
+       t *testing.T,
+       f *fory.Fory,
+       collections collection.NumericCollections,
+       unionValue collection.NumericCollectionUnion,
+       collectionsArray collection.NumericCollectionsArray,
+       arrayUnion collection.NumericCollectionArrayUnion,
+) {
+       dataFile := os.Getenv("DATA_FILE_COLLECTION")
+       if dataFile != "" {
+               payload, err := os.ReadFile(dataFile)
+               if err != nil {
+                       t.Fatalf("read collection file: %v", err)
+               }
+               var decoded collection.NumericCollections
+               if err := f.Deserialize(payload, &decoded); err != nil {
+                       t.Fatalf("deserialize collection file: %v", err)
+               }
+               if !reflect.DeepEqual(collections, decoded) {
+                       t.Fatalf("collection file mismatch: %#v != %#v", 
collections, decoded)
+               }
+               out, err := f.Serialize(&decoded)
+               if err != nil {
+                       t.Fatalf("serialize collection file: %v", err)
+               }
+               if err := os.WriteFile(dataFile, out, 0o644); err != nil {
+                       t.Fatalf("write collection file: %v", err)
+               }
+       }
+
+       unionFile := os.Getenv("DATA_FILE_COLLECTION_UNION")
+       if unionFile != "" {
+               payload, err := os.ReadFile(unionFile)
+               if err != nil {
+                       t.Fatalf("read collection union file: %v", err)
+               }
+               var decoded collection.NumericCollectionUnion
+               if err := f.Deserialize(payload, &decoded); err != nil {
+                       t.Fatalf("deserialize collection union file: %v", err)
+               }
+               if !reflect.DeepEqual(unionValue, decoded) {
+                       t.Fatalf("collection union file mismatch: %#v != %#v", 
unionValue, decoded)
+               }
+               out, err := f.Serialize(&decoded)
+               if err != nil {
+                       t.Fatalf("serialize collection union file: %v", err)
+               }
+               if err := os.WriteFile(unionFile, out, 0o644); err != nil {
+                       t.Fatalf("write collection union file: %v", err)
+               }
+       }
+
+       arrayFile := os.Getenv("DATA_FILE_COLLECTION_ARRAY")
+       if arrayFile != "" {
+               payload, err := os.ReadFile(arrayFile)
+               if err != nil {
+                       t.Fatalf("read collection array file: %v", err)
+               }
+               var decoded collection.NumericCollectionsArray
+               if err := f.Deserialize(payload, &decoded); err != nil {
+                       t.Fatalf("deserialize collection array file: %v", err)
+               }
+               if !reflect.DeepEqual(collectionsArray, decoded) {
+                       t.Fatalf("collection array file mismatch: %#v != %#v", 
collectionsArray, decoded)
+               }
+               out, err := f.Serialize(&decoded)
+               if err != nil {
+                       t.Fatalf("serialize collection array file: %v", err)
+               }
+               if err := os.WriteFile(arrayFile, out, 0o644); err != nil {
+                       t.Fatalf("write collection array file: %v", err)
+               }
+       }
+
+       arrayUnionFile := os.Getenv("DATA_FILE_COLLECTION_ARRAY_UNION")
+       if arrayUnionFile != "" {
+               payload, err := os.ReadFile(arrayUnionFile)
+               if err != nil {
+                       t.Fatalf("read collection array union file: %v", err)
+               }
+               var decoded collection.NumericCollectionArrayUnion
+               if err := f.Deserialize(payload, &decoded); err != nil {
+                       t.Fatalf("deserialize collection array union file: %v", 
err)
+               }
+               if !reflect.DeepEqual(arrayUnion, decoded) {
+                       t.Fatalf("collection array union file mismatch: %#v != 
%#v", arrayUnion, decoded)
+               }
+               out, err := f.Serialize(&decoded)
+               if err != nil {
+                       t.Fatalf("serialize collection array union file: %v", 
err)
+               }
+               if err := os.WriteFile(arrayUnionFile, out, 0o644); err != nil {
+                       t.Fatalf("write collection array union file: %v", err)
+               }
+       }
+}
+
 func buildMonster() monster.Monster {
        pos := &monster.Vec3{
                X: 1.0,
diff --git a/integration_tests/idl_tests/idl/collection.fdl 
b/integration_tests/idl_tests/idl/collection.fdl
new file mode 100644
index 000000000..091f11243
--- /dev/null
+++ b/integration_tests/idl_tests/idl/collection.fdl
@@ -0,0 +1,70 @@
+// 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 collection;
+
+message NumericCollections [id=210] {
+    repeated int8 int8_values = 1;
+    repeated int16 int16_values = 2;
+    repeated int32 int32_values = 3;
+    repeated int64 int64_values = 4;
+    repeated uint8 uint8_values = 5;
+    repeated uint16 uint16_values = 6;
+    repeated uint32 uint32_values = 7;
+    repeated uint64 uint64_values = 8;
+    repeated float32 float32_values = 9;
+    repeated float64 float64_values = 10;
+}
+
+union NumericCollectionUnion [id=211] {
+    repeated int8 int8_values = 1;
+    repeated int16 int16_values = 2;
+    repeated int32 int32_values = 3;
+    repeated int64 int64_values = 4;
+    repeated uint8 uint8_values = 5;
+    repeated uint16 uint16_values = 6;
+    repeated uint32 uint32_values = 7;
+    repeated uint64 uint64_values = 8;
+    repeated float32 float32_values = 9;
+    repeated float64 float64_values = 10;
+}
+
+message NumericCollectionsArray [id=212] {
+    repeated int8 int8_values = 1 [java_array = true];
+    repeated int16 int16_values = 2 [java_array = true];
+    repeated int32 int32_values = 3 [java_array = true];
+    repeated int64 int64_values = 4 [java_array = true];
+    repeated uint8 uint8_values = 5 [java_array = true];
+    repeated uint16 uint16_values = 6 [java_array = true];
+    repeated uint32 uint32_values = 7 [java_array = true];
+    repeated uint64 uint64_values = 8 [java_array = true];
+    repeated float32 float32_values = 9 [java_array = true];
+    repeated float64 float64_values = 10 [java_array = true];
+}
+
+union NumericCollectionArrayUnion [id=213] {
+    repeated int8 int8_values = 1 [java_array = true];
+    repeated int16 int16_values = 2 [java_array = true];
+    repeated int32 int32_values = 3 [java_array = true];
+    repeated int64 int64_values = 4 [java_array = true];
+    repeated uint8 uint8_values = 5 [java_array = true];
+    repeated uint16 uint16_values = 6 [java_array = true];
+    repeated uint32 uint32_values = 7 [java_array = true];
+    repeated uint64 uint64_values = 8 [java_array = true];
+    repeated float32 float32_values = 9 [java_array = true];
+    repeated float64 float64_values = 10 [java_array = true];
+}
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 ff64b0977..dfec1d79a 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,11 @@ import addressbook.Dog;
 import addressbook.Person;
 import addressbook.Person.PhoneNumber;
 import addressbook.Person.PhoneType;
+import collection.CollectionForyRegistration;
+import collection.NumericCollectionArrayUnion;
+import collection.NumericCollectionUnion;
+import collection.NumericCollections;
+import collection.NumericCollectionsArray;
 import complex_pb.ComplexPbForyRegistration;
 import complex_pb.PrimitiveTypes;
 import any_example.AnyExampleForyRegistration;
@@ -71,6 +76,14 @@ import java.util.Map;
 import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 import org.apache.fory.Fory;
+import org.apache.fory.collection.Int16List;
+import org.apache.fory.collection.Int32List;
+import org.apache.fory.collection.Int64List;
+import org.apache.fory.collection.Int8List;
+import org.apache.fory.collection.Uint16List;
+import org.apache.fory.collection.Uint32List;
+import org.apache.fory.collection.Uint64List;
+import org.apache.fory.collection.Uint8List;
 import org.apache.fory.config.CompatibleMode;
 import org.apache.fory.config.Language;
 import org.testng.Assert;
@@ -204,6 +217,93 @@ public class IdlRoundTripTest {
     }
   }
 
+  @Test
+  public void testCollectionRoundTripCompatible() throws Exception {
+    runCollectionRoundTrip(true);
+  }
+
+  @Test
+  public void testCollectionRoundTripSchemaConsistent() throws Exception {
+    runCollectionRoundTrip(false);
+  }
+
+  private void runCollectionRoundTrip(boolean compatible) throws Exception {
+    Fory fory = buildFory(compatible);
+    CollectionForyRegistration.register(fory);
+
+    NumericCollections collections = buildNumericCollections();
+    NumericCollectionUnion collectionUnion = buildNumericCollectionUnion();
+    NumericCollectionsArray collectionsArray = buildNumericCollectionsArray();
+    NumericCollectionArrayUnion collectionArrayUnion = 
buildNumericCollectionArrayUnion();
+
+    byte[] collectionsBytes = fory.serialize(collections);
+    Object collectionsDecoded = fory.deserialize(collectionsBytes);
+    Assert.assertTrue(collectionsDecoded instanceof NumericCollections);
+    Assert.assertEquals(collectionsDecoded, collections);
+
+    byte[] unionBytes = fory.serialize(collectionUnion);
+    Object unionDecoded = fory.deserialize(unionBytes);
+    assertNumericCollectionUnion(unionDecoded, collectionUnion);
+
+    byte[] arrayBytes = fory.serialize(collectionsArray);
+    Object arrayDecoded = fory.deserialize(arrayBytes);
+    Assert.assertTrue(arrayDecoded instanceof NumericCollectionsArray);
+    Assert.assertEquals(arrayDecoded, collectionsArray);
+
+    byte[] arrayUnionBytes = fory.serialize(collectionArrayUnion);
+    Object arrayUnionDecoded = fory.deserialize(arrayUnionBytes);
+    assertNumericCollectionArrayUnion(arrayUnionDecoded, collectionArrayUnion);
+
+    for (String peer : resolvePeers()) {
+      Path collectionsFile =
+          Files.createTempFile("idl-collections-" + peer + "-", ".bin");
+      collectionsFile.toFile().deleteOnExit();
+      Files.write(collectionsFile, collectionsBytes);
+
+      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");
+      arrayFile.toFile().deleteOnExit();
+      Files.write(arrayFile, arrayBytes);
+
+      Path arrayUnionFile =
+          Files.createTempFile("idl-collection-array-union-" + peer + "-", 
".bin");
+      arrayUnionFile.toFile().deleteOnExit();
+      Files.write(arrayUnionFile, arrayUnionBytes);
+
+      Map<String, String> env = new HashMap<>();
+      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());
+      PeerCommand command = buildPeerCommand(peer, env, compatible);
+      runPeer(command, peer);
+
+      byte[] peerCollectionsBytes = Files.readAllBytes(collectionsFile);
+      Object collectionsRoundTrip = fory.deserialize(peerCollectionsBytes);
+      Assert.assertTrue(collectionsRoundTrip instanceof NumericCollections);
+      Assert.assertEquals(collectionsRoundTrip, collections);
+
+      byte[] peerUnionBytes = Files.readAllBytes(unionFile);
+      Object unionRoundTrip = fory.deserialize(peerUnionBytes);
+      assertNumericCollectionUnion(unionRoundTrip, collectionUnion);
+
+      byte[] peerArrayBytes = Files.readAllBytes(arrayFile);
+      Object arrayRoundTrip = fory.deserialize(peerArrayBytes);
+      Assert.assertTrue(arrayRoundTrip instanceof NumericCollectionsArray);
+      Assert.assertEquals(arrayRoundTrip, collectionsArray);
+
+      byte[] peerArrayUnionBytes = Files.readAllBytes(arrayUnionFile);
+      Object arrayUnionRoundTrip = fory.deserialize(peerArrayUnionBytes);
+      assertNumericCollectionArrayUnion(arrayUnionRoundTrip, 
collectionArrayUnion);
+    }
+  }
+
   @Test
   public void testOptionalTypesRoundTripCompatible() throws Exception {
     runOptionalTypesRoundTrip(true);
@@ -591,6 +691,76 @@ public class IdlRoundTripTest {
     return types;
   }
 
+  private NumericCollections buildNumericCollections() {
+    NumericCollections collections = new NumericCollections();
+    collections.setInt8Values(new Int8List(new byte[] {1, -2, 3}));
+    collections.setInt16Values(new Int16List(new short[] {100, -200, 300}));
+    collections.setInt32Values(new Int32List(new int[] {1000, -2000, 3000}));
+    collections.setInt64Values(new Int64List(new long[] {10000L, -20000L, 
30000L}));
+    collections.setUint8Values(new Uint8List(new byte[] {(byte) 200, (byte) 
250}));
+    collections.setUint16Values(new Uint16List(new short[] {(short) 50000, 
(short) 60000}));
+    collections.setUint32Values(new Uint32List(new int[] {2000000000, 
2100000000}));
+    collections.setUint64Values(new Uint64List(new long[] {9000000000L, 
12000000000L}));
+    collections.setFloat32Values(new float[] {1.5f, 2.5f});
+    collections.setFloat64Values(new double[] {3.5d, 4.5d});
+    return collections;
+  }
+
+  private NumericCollectionUnion buildNumericCollectionUnion() {
+    return NumericCollectionUnion.ofInt32Values(new Int32List(new int[] {7, 8, 
9}));
+  }
+
+  private NumericCollectionsArray buildNumericCollectionsArray() {
+    NumericCollectionsArray collections = new NumericCollectionsArray();
+    collections.setInt8Values(new byte[] {1, -2, 3});
+    collections.setInt16Values(new short[] {100, -200, 300});
+    collections.setInt32Values(new int[] {1000, -2000, 3000});
+    collections.setInt64Values(new long[] {10000L, -20000L, 30000L});
+    collections.setUint8Values(new byte[] {(byte) 200, (byte) 250});
+    collections.setUint16Values(new short[] {(short) 50000, (short) 60000});
+    collections.setUint32Values(new int[] {2000000000, 2100000000});
+    collections.setUint64Values(new long[] {9000000000L, 12000000000L});
+    collections.setFloat32Values(new float[] {1.5f, 2.5f});
+    collections.setFloat64Values(new double[] {3.5d, 4.5d});
+    return collections;
+  }
+
+  private NumericCollectionArrayUnion buildNumericCollectionArrayUnion() {
+    return NumericCollectionArrayUnion.ofUint16Values(new short[] {1000, 2000, 
3000});
+  }
+
+  private void assertNumericCollectionUnion(
+      Object decoded, NumericCollectionUnion expected) {
+    Assert.assertTrue(decoded instanceof NumericCollectionUnion);
+    NumericCollectionUnion union = (NumericCollectionUnion) decoded;
+    Assert.assertEquals(union.getNumericCollectionUnionCase(), 
expected.getNumericCollectionUnionCase());
+    switch (union.getNumericCollectionUnionCase()) {
+      case INT32_VALUES:
+        Assert.assertEquals(union.getInt32Values(), expected.getInt32Values());
+        break;
+      default:
+        Assert.fail("Unexpected union case: " + 
union.getNumericCollectionUnionCase());
+    }
+  }
+
+  private void assertNumericCollectionArrayUnion(
+      Object decoded, NumericCollectionArrayUnion expected) {
+    Assert.assertTrue(decoded instanceof NumericCollectionArrayUnion);
+    NumericCollectionArrayUnion union = (NumericCollectionArrayUnion) decoded;
+    Assert.assertEquals(
+        union.getNumericCollectionArrayUnionCase(),
+        expected.getNumericCollectionArrayUnionCase());
+    switch (union.getNumericCollectionArrayUnionCase()) {
+      case UINT16_VALUES:
+        Assert.assertTrue(
+            Arrays.equals(union.getUint16Values(), 
expected.getUint16Values()));
+        break;
+      default:
+        Assert.fail(
+            "Unexpected array union case: " + 
union.getNumericCollectionArrayUnionCase());
+    }
+  }
+
   private Monster buildMonster() {
     Vec3 pos = new Vec3();
     pos.setX(1.0f);
@@ -603,7 +773,7 @@ public class IdlRoundTripTest {
     monster.setHp((short) 80);
     monster.setName("Orc");
     monster.setFriendly(true);
-    monster.setInventory(new byte[] {(byte) 1, (byte) 2, (byte) 3});
+    monster.setInventory(new Uint8List(new byte[] {(byte) 1, (byte) 2, (byte) 
3}));
     monster.setColor(Color.Blue);
     return monster;
   }
@@ -635,7 +805,7 @@ public class IdlRoundTripTest {
     allTypes.setBytesValue(new byte[] {1, 2, 3});
     allTypes.setDateValue(LocalDate.of(2024, 1, 2));
     allTypes.setTimestampValue(Instant.parse("2024-01-02T03:04:05Z"));
-    allTypes.setInt32List(new int[] {1, 2, 3});
+    allTypes.setInt32List(new Int32List(new int[] {1, 2, 3}));
     allTypes.setStringList(Arrays.asList("alpha", "beta"));
     Map<String, Long> int64Map = new HashMap<>();
     int64Map.put("alpha", 10L);
@@ -749,8 +919,8 @@ public class IdlRoundTripTest {
     Container container = new Container();
     container.setId(9876543210L);
     container.setStatus(Status.STARTED);
-    container.setBytes(new byte[] {(byte) 1, (byte) 2, (byte) 3});
-    container.setNumbers(new int[] {10, 20, 30});
+    container.setBytes(new Int8List(new byte[] {(byte) 1, (byte) 2, (byte) 
3}));
+    container.setNumbers(new Int32List(new int[] {10, 20, 30}));
     container.setScalars(pack);
     container.setNames(Arrays.asList("alpha", "beta"));
     container.setFlags(new boolean[] {true, false});
diff --git a/integration_tests/idl_tests/python/src/idl_tests/roundtrip.py 
b/integration_tests/idl_tests/python/src/idl_tests/roundtrip.py
index 7cc573880..869d079e0 100644
--- a/integration_tests/idl_tests/python/src/idl_tests/roundtrip.py
+++ b/integration_tests/idl_tests/python/src/idl_tests/roundtrip.py
@@ -25,6 +25,7 @@ import addressbook
 import any_example
 import complex_fbs
 import complex_pb
+import collection
 import monster
 import optional_types
 import graph
@@ -153,6 +154,106 @@ def build_primitive_types() -> 
"complex_pb.PrimitiveTypes":
     )
 
 
+def build_numeric_collections() -> "collection.NumericCollections":
+    return collection.NumericCollections(
+        int8_values=np.array([1, -2, 3], dtype=np.int8),
+        int16_values=np.array([100, -200, 300], dtype=np.int16),
+        int32_values=np.array([1000, -2000, 3000], dtype=np.int32),
+        int64_values=np.array([10000, -20000, 30000], dtype=np.int64),
+        uint8_values=np.array([200, 250], dtype=np.uint8),
+        uint16_values=np.array([50000, 60000], dtype=np.uint16),
+        uint32_values=np.array([2000000000, 2100000000], dtype=np.uint32),
+        uint64_values=np.array([9000000000, 12000000000], dtype=np.uint64),
+        float32_values=np.array([1.5, 2.5], dtype=np.float32),
+        float64_values=np.array([3.5, 4.5], dtype=np.float64),
+    )
+
+
+def build_numeric_collection_union() -> "collection.NumericCollectionUnion":
+    return collection.NumericCollectionUnion.int32_values(
+        np.array([7, 8, 9], dtype=np.int32)
+    )
+
+
+def build_numeric_collections_array() -> "collection.NumericCollectionsArray":
+    return collection.NumericCollectionsArray(
+        int8_values=np.array([1, -2, 3], dtype=np.int8),
+        int16_values=np.array([100, -200, 300], dtype=np.int16),
+        int32_values=np.array([1000, -2000, 3000], dtype=np.int32),
+        int64_values=np.array([10000, -20000, 30000], dtype=np.int64),
+        uint8_values=np.array([200, 250], dtype=np.uint8),
+        uint16_values=np.array([50000, 60000], dtype=np.uint16),
+        uint32_values=np.array([2000000000, 2100000000], dtype=np.uint32),
+        uint64_values=np.array([9000000000, 12000000000], dtype=np.uint64),
+        float32_values=np.array([1.5, 2.5], dtype=np.float32),
+        float64_values=np.array([3.5, 4.5], dtype=np.float64),
+    )
+
+
+def build_numeric_collection_array_union() -> 
"collection.NumericCollectionArrayUnion":
+    return collection.NumericCollectionArrayUnion.uint16_values(
+        np.array([1000, 2000, 3000], dtype=np.uint16)
+    )
+
+
+def assert_numeric_collections_equal(
+    decoded: "collection.NumericCollections",
+    expected: "collection.NumericCollections",
+) -> None:
+    assert np.array_equal(decoded.int8_values, expected.int8_values)
+    assert np.array_equal(decoded.int16_values, expected.int16_values)
+    assert np.array_equal(decoded.int32_values, expected.int32_values)
+    assert np.array_equal(decoded.int64_values, expected.int64_values)
+    assert np.array_equal(decoded.uint8_values, expected.uint8_values)
+    assert np.array_equal(decoded.uint16_values, expected.uint16_values)
+    assert np.array_equal(decoded.uint32_values, expected.uint32_values)
+    assert np.array_equal(decoded.uint64_values, expected.uint64_values)
+    assert np.array_equal(decoded.float32_values, expected.float32_values)
+    assert np.array_equal(decoded.float64_values, expected.float64_values)
+
+
+def assert_numeric_collections_array_equal(
+    decoded: "collection.NumericCollectionsArray",
+    expected: "collection.NumericCollectionsArray",
+) -> None:
+    assert np.array_equal(decoded.int8_values, expected.int8_values)
+    assert np.array_equal(decoded.int16_values, expected.int16_values)
+    assert np.array_equal(decoded.int32_values, expected.int32_values)
+    assert np.array_equal(decoded.int64_values, expected.int64_values)
+    assert np.array_equal(decoded.uint8_values, expected.uint8_values)
+    assert np.array_equal(decoded.uint16_values, expected.uint16_values)
+    assert np.array_equal(decoded.uint32_values, expected.uint32_values)
+    assert np.array_equal(decoded.uint64_values, expected.uint64_values)
+    assert np.array_equal(decoded.float32_values, expected.float32_values)
+    assert np.array_equal(decoded.float64_values, expected.float64_values)
+
+
+def assert_numeric_collection_union_equal(
+    decoded: "collection.NumericCollectionUnion",
+    expected: "collection.NumericCollectionUnion",
+) -> None:
+    assert decoded.case() == expected.case()
+    if decoded.case() == collection.NumericCollectionUnionCase.INT32_VALUES:
+        assert np.array_equal(
+            decoded.int32_values_value(), expected.int32_values_value()
+        )
+        return
+    raise AssertionError(f"unexpected union case: {decoded.case()}")
+
+
+def assert_numeric_collection_array_union_equal(
+    decoded: "collection.NumericCollectionArrayUnion",
+    expected: "collection.NumericCollectionArrayUnion",
+) -> None:
+    assert decoded.case() == expected.case()
+    if decoded.case() == 
collection.NumericCollectionArrayUnionCase.UINT16_VALUES:
+        assert np.array_equal(
+            decoded.uint16_values_value(), expected.uint16_values_value()
+        )
+        return
+    raise AssertionError(f"unexpected union case: {decoded.case()}")
+
+
 def build_optional_holder() -> "optional_types.OptionalHolder":
     all_types = optional_types.AllOptionalTypes(
         bool_value=True,
@@ -340,6 +441,70 @@ def file_roundtrip_primitives(
     Path(data_file).write_bytes(fory.serialize(decoded))
 
 
+def local_roundtrip_collections(
+    fory: pyfory.Fory,
+    collections_value: "collection.NumericCollections",
+    union_value: "collection.NumericCollectionUnion",
+    array_value: "collection.NumericCollectionsArray",
+    array_union_value: "collection.NumericCollectionArrayUnion",
+) -> None:
+    decoded = fory.deserialize(fory.serialize(collections_value))
+    assert isinstance(decoded, collection.NumericCollections)
+    assert_numeric_collections_equal(decoded, collections_value)
+
+    decoded_union = fory.deserialize(fory.serialize(union_value))
+    assert isinstance(decoded_union, collection.NumericCollectionUnion)
+    assert_numeric_collection_union_equal(decoded_union, union_value)
+
+    decoded_array = fory.deserialize(fory.serialize(array_value))
+    assert isinstance(decoded_array, collection.NumericCollectionsArray)
+    assert_numeric_collections_array_equal(decoded_array, array_value)
+
+    decoded_array_union = fory.deserialize(fory.serialize(array_union_value))
+    assert isinstance(decoded_array_union, 
collection.NumericCollectionArrayUnion)
+    assert_numeric_collection_array_union_equal(decoded_array_union, 
array_union_value)
+
+
+def file_roundtrip_collections(
+    fory: pyfory.Fory,
+    collections_value: "collection.NumericCollections",
+    union_value: "collection.NumericCollectionUnion",
+    array_value: "collection.NumericCollectionsArray",
+    array_union_value: "collection.NumericCollectionArrayUnion",
+) -> None:
+    data_file = os.environ.get("DATA_FILE_COLLECTION")
+    if data_file:
+        payload = Path(data_file).read_bytes()
+        decoded = fory.deserialize(payload)
+        assert isinstance(decoded, collection.NumericCollections)
+        assert_numeric_collections_equal(decoded, collections_value)
+        Path(data_file).write_bytes(fory.serialize(decoded))
+
+    union_file = os.environ.get("DATA_FILE_COLLECTION_UNION")
+    if union_file:
+        payload = Path(union_file).read_bytes()
+        decoded = fory.deserialize(payload)
+        assert isinstance(decoded, collection.NumericCollectionUnion)
+        assert_numeric_collection_union_equal(decoded, union_value)
+        Path(union_file).write_bytes(fory.serialize(decoded))
+
+    array_file = os.environ.get("DATA_FILE_COLLECTION_ARRAY")
+    if array_file:
+        payload = Path(array_file).read_bytes()
+        decoded = fory.deserialize(payload)
+        assert isinstance(decoded, collection.NumericCollectionsArray)
+        assert_numeric_collections_array_equal(decoded, array_value)
+        Path(array_file).write_bytes(fory.serialize(decoded))
+
+    array_union_file = os.environ.get("DATA_FILE_COLLECTION_ARRAY_UNION")
+    if array_union_file:
+        payload = Path(array_union_file).read_bytes()
+        decoded = fory.deserialize(payload)
+        assert isinstance(decoded, collection.NumericCollectionArrayUnion)
+        assert_numeric_collection_array_union_equal(decoded, array_union_value)
+        Path(array_union_file).write_bytes(fory.serialize(decoded))
+
+
 def assert_optional_types_equal(
     decoded: "optional_types.AllOptionalTypes",
     expected: "optional_types.AllOptionalTypes",
@@ -506,6 +671,7 @@ def run_roundtrip(compatible: bool) -> None:
     addressbook.register_addressbook_types(fory)
     monster.register_monster_types(fory)
     complex_fbs.register_complex_fbs_types(fory)
+    collection.register_collection_types(fory)
     optional_types.register_optional_types_types(fory)
     any_example.register_any_example_types(fory)
 
@@ -519,6 +685,17 @@ def run_roundtrip(compatible: bool) -> None:
     local_roundtrip_primitives(fory, primitives)
     file_roundtrip_primitives(fory, primitives)
 
+    collections_value = build_numeric_collections()
+    union_value = build_numeric_collection_union()
+    array_value = build_numeric_collections_array()
+    array_union_value = build_numeric_collection_array_union()
+    local_roundtrip_collections(
+        fory, collections_value, union_value, array_value, array_union_value
+    )
+    file_roundtrip_collections(
+        fory, collections_value, union_value, array_value, array_union_value
+    )
+
     monster_value = build_monster()
     local_roundtrip_monster(fory, monster_value)
     file_roundtrip_monster(fory, monster_value)
diff --git a/integration_tests/idl_tests/rust/src/lib.rs 
b/integration_tests/idl_tests/rust/src/lib.rs
index cc601bd6b..47e0e4b70 100644
--- a/integration_tests/idl_tests/rust/src/lib.rs
+++ b/integration_tests/idl_tests/rust/src/lib.rs
@@ -20,6 +20,7 @@ pub mod any_example;
 pub mod any_example_pb;
 pub mod complex_fbs;
 pub mod complex_pb;
+pub mod collection;
 pub mod monster;
 pub mod root;
 pub mod optional_types;
diff --git a/integration_tests/idl_tests/rust/tests/idl_roundtrip.rs 
b/integration_tests/idl_tests/rust/tests/idl_roundtrip.rs
index ec95b5e87..82c549938 100644
--- a/integration_tests/idl_tests/rust/tests/idl_roundtrip.rs
+++ b/integration_tests/idl_tests/rust/tests/idl_roundtrip.rs
@@ -28,6 +28,7 @@ use idl_tests::addressbook::{
 };
 use idl_tests::complex_pb::{self, PrimitiveTypes};
 use idl_tests::complex_fbs::{self, Container, Note, Payload, ScalarPack, 
Status};
+use idl_tests::collection::{self, NumericCollectionArrayUnion, 
NumericCollectionUnion, NumericCollections, NumericCollectionsArray};
 use idl_tests::monster::{self, Color, Monster, Vec3};
 use idl_tests::optional_types::{self, AllOptionalTypes, OptionalHolder, 
OptionalUnion};
 use idl_tests::any_example::{self, AnyHolder, AnyInner, AnyUnion};
@@ -155,6 +156,44 @@ fn build_primitive_types() -> PrimitiveTypes {
     }
 }
 
+fn build_numeric_collections() -> NumericCollections {
+    NumericCollections {
+        int8_values: vec![1, -2, 3],
+        int16_values: vec![100, -200, 300],
+        int32_values: vec![1000, -2000, 3000],
+        int64_values: vec![10000, -20000, 30000],
+        uint8_values: vec![200, 250],
+        uint16_values: vec![50000, 60000],
+        uint32_values: vec![2000000000, 2100000000],
+        uint64_values: vec![9000000000, 12000000000],
+        float32_values: vec![1.5, 2.5],
+        float64_values: vec![3.5, 4.5],
+    }
+}
+
+fn build_numeric_collection_union() -> NumericCollectionUnion {
+    NumericCollectionUnion::Int32Values(vec![7, 8, 9])
+}
+
+fn build_numeric_collections_array() -> NumericCollectionsArray {
+    NumericCollectionsArray {
+        int8_values: vec![1, -2, 3],
+        int16_values: vec![100, -200, 300],
+        int32_values: vec![1000, -2000, 3000],
+        int64_values: vec![10000, -20000, 30000],
+        uint8_values: vec![200, 250],
+        uint16_values: vec![50000, 60000],
+        uint32_values: vec![2000000000, 2100000000],
+        uint64_values: vec![9000000000, 12000000000],
+        float32_values: vec![1.5, 2.5],
+        float64_values: vec![3.5, 4.5],
+    }
+}
+
+fn build_numeric_collection_array_union() -> NumericCollectionArrayUnion {
+    NumericCollectionArrayUnion::Uint16Values(vec![1000, 2000, 3000])
+}
+
 fn build_monster() -> Monster {
     let pos = Vec3 {
         x: 1.0,
@@ -451,6 +490,7 @@ fn run_address_book_roundtrip(compatible: bool) {
     addressbook::register_types(&mut fory).expect("register types");
     monster::register_types(&mut fory).expect("register monster types");
     complex_fbs::register_types(&mut fory).expect("register flatbuffers 
types");
+    collection::register_types(&mut fory).expect("register collection types");
     optional_types::register_types(&mut fory).expect("register optional 
types");
     any_example::register_types(&mut fory).expect("register any example 
types");
 
@@ -489,6 +529,81 @@ fn run_address_book_roundtrip(compatible: bool) {
     let encoded = fory.serialize(&peer_types).expect("serialize peer payload");
     fs::write(primitive_file, encoded).expect("write data file");
 
+    let collections = build_numeric_collections();
+    let bytes = fory.serialize(&collections).expect("serialize collections");
+    let roundtrip: NumericCollections = 
fory.deserialize(&bytes).expect("deserialize");
+    assert_eq!(collections, roundtrip);
+
+    if let Ok(data_file) = env::var("DATA_FILE_COLLECTION") {
+        let payload = fs::read(&data_file).expect("read data file");
+        let peer_collections: NumericCollections = fory
+            .deserialize(&payload)
+            .expect("deserialize peer payload");
+        assert_eq!(collections, peer_collections);
+        let encoded = fory
+            .serialize(&peer_collections)
+            .expect("serialize peer payload");
+        fs::write(data_file, encoded).expect("write data file");
+    }
+
+    let collection_union = build_numeric_collection_union();
+    let bytes = fory
+        .serialize(&collection_union)
+        .expect("serialize collection union");
+    let roundtrip: NumericCollectionUnion = 
fory.deserialize(&bytes).expect("deserialize");
+    assert_eq!(collection_union, roundtrip);
+
+    if let Ok(data_file) = env::var("DATA_FILE_COLLECTION_UNION") {
+        let payload = fs::read(&data_file).expect("read data file");
+        let peer_union: NumericCollectionUnion = fory
+            .deserialize(&payload)
+            .expect("deserialize peer payload");
+        assert_eq!(collection_union, peer_union);
+        let encoded = fory
+            .serialize(&peer_union)
+            .expect("serialize peer payload");
+        fs::write(data_file, encoded).expect("write data file");
+    }
+
+    let collections_array = build_numeric_collections_array();
+    let bytes = fory
+        .serialize(&collections_array)
+        .expect("serialize collection array");
+    let roundtrip: NumericCollectionsArray = 
fory.deserialize(&bytes).expect("deserialize");
+    assert_eq!(collections_array, roundtrip);
+
+    if let Ok(data_file) = env::var("DATA_FILE_COLLECTION_ARRAY") {
+        let payload = fs::read(&data_file).expect("read data file");
+        let peer_array: NumericCollectionsArray = fory
+            .deserialize(&payload)
+            .expect("deserialize peer payload");
+        assert_eq!(collections_array, peer_array);
+        let encoded = fory
+            .serialize(&peer_array)
+            .expect("serialize peer payload");
+        fs::write(data_file, encoded).expect("write data file");
+    }
+
+    let collection_array_union = build_numeric_collection_array_union();
+    let bytes = fory
+        .serialize(&collection_array_union)
+        .expect("serialize collection array union");
+    let roundtrip: NumericCollectionArrayUnion =
+        fory.deserialize(&bytes).expect("deserialize");
+    assert_eq!(collection_array_union, roundtrip);
+
+    if let Ok(data_file) = env::var("DATA_FILE_COLLECTION_ARRAY_UNION") {
+        let payload = fs::read(&data_file).expect("read data file");
+        let peer_union: NumericCollectionArrayUnion = fory
+            .deserialize(&payload)
+            .expect("deserialize peer payload");
+        assert_eq!(collection_array_union, peer_union);
+        let encoded = fory
+            .serialize(&peer_union)
+            .expect("serialize peer payload");
+        fs::write(data_file, encoded).expect("write data file");
+    }
+
     let monster = build_monster();
     let bytes = fory.serialize(&monster).expect("serialize");
     let roundtrip: Monster = fory.deserialize(&bytes).expect("deserialize");
diff --git 
a/java/fory-core/src/main/java/org/apache/fory/collection/Int16List.java 
b/java/fory-core/src/main/java/org/apache/fory/collection/Int16List.java
index 57f8356c3..90116cd7e 100644
--- a/java/fory-core/src/main/java/org/apache/fory/collection/Int16List.java
+++ b/java/fory-core/src/main/java/org/apache/fory/collection/Int16List.java
@@ -145,7 +145,31 @@ public final class Int16List extends AbstractList<Short> 
implements RandomAccess
     return true;
   }
 
-  /** Returns the live backing array; elements beyond {@code size()} are 
undefined. */
+  /**
+   * Returns {@code true} if this list is backed by an accessible heap array.
+   *
+   * <p>If this method returns {@code true}, then {@link #getArray()} may be 
safely called to obtain
+   * the underlying storage without incurring a data copy.
+   *
+   * @return {@code true} if this list is backed by a primitive array and is 
not read-only
+   */
+  public boolean hasArray() {
+    return array != null;
+  }
+
+  /**
+   * Returns the underlying heap array that backs this list.
+   *
+   * <p><b>Warning:</b> Users should check {@link #hasArray()} before calling 
this method. If {@code
+   * hasArray()} returns {@code false}, this method will return a copy that 
does not reflect
+   * subsequent mutations.
+   *
+   * <p>Modifying the returned array will directly affect the list, and vice 
versa. Elements beyond
+   * {@link #size()} are undefined.
+   *
+   * @return the backing array
+   * @throws UnsupportedOperationException if this list is not backed by an 
accessible heap array
+   */
   public short[] getArray() {
     return array;
   }
diff --git 
a/java/fory-core/src/main/java/org/apache/fory/collection/Int32List.java 
b/java/fory-core/src/main/java/org/apache/fory/collection/Int32List.java
index 082e4f82e..59802b70e 100644
--- a/java/fory-core/src/main/java/org/apache/fory/collection/Int32List.java
+++ b/java/fory-core/src/main/java/org/apache/fory/collection/Int32List.java
@@ -140,7 +140,31 @@ public final class Int32List extends AbstractList<Integer> 
implements RandomAcce
     return true;
   }
 
-  /** Returns the live backing array; elements beyond {@code size()} are 
undefined. */
+  /**
+   * Returns {@code true} if this list is backed by an accessible heap array.
+   *
+   * <p>If this method returns {@code true}, then {@link #getArray()} may be 
safely called to obtain
+   * the underlying storage without incurring a data copy.
+   *
+   * @return {@code true} if this list is backed by a primitive array and is 
not read-only
+   */
+  public boolean hasArray() {
+    return array != null;
+  }
+
+  /**
+   * Returns the underlying heap array that backs this list.
+   *
+   * <p><b>Warning:</b> Users should check {@link #hasArray()} before calling 
this method. If {@code
+   * hasArray()} returns {@code false}, this method will return a copy that 
does not reflect
+   * subsequent mutations.
+   *
+   * <p>Modifying the returned array will directly affect the list, and vice 
versa. Elements beyond
+   * {@link #size()} are undefined.
+   *
+   * @return the backing array
+   * @throws UnsupportedOperationException if this list is not backed by an 
accessible heap array
+   */
   public int[] getArray() {
     return array;
   }
diff --git 
a/java/fory-core/src/main/java/org/apache/fory/collection/Int64List.java 
b/java/fory-core/src/main/java/org/apache/fory/collection/Int64List.java
index a80b5801f..adae411f7 100644
--- a/java/fory-core/src/main/java/org/apache/fory/collection/Int64List.java
+++ b/java/fory-core/src/main/java/org/apache/fory/collection/Int64List.java
@@ -126,7 +126,31 @@ public final class Int64List extends AbstractList<Long> 
implements RandomAccess
     return true;
   }
 
-  /** Returns the live backing array; elements beyond {@code size()} are 
undefined. */
+  /**
+   * Returns {@code true} if this list is backed by an accessible heap array.
+   *
+   * <p>If this method returns {@code true}, then {@link #getArray()} may be 
safely called to obtain
+   * the underlying storage without incurring a data copy.
+   *
+   * @return {@code true} if this list is backed by a primitive array and is 
not read-only
+   */
+  public boolean hasArray() {
+    return array != null;
+  }
+
+  /**
+   * Returns the underlying heap array that backs this list.
+   *
+   * <p><b>Warning:</b> Users should check {@link #hasArray()} before calling 
this method. If {@code
+   * hasArray()} returns {@code false}, this method will return a copy that 
does not reflect
+   * subsequent mutations.
+   *
+   * <p>Modifying the returned array will directly affect the list, and vice 
versa. Elements beyond
+   * {@link #size()} are undefined.
+   *
+   * @return the backing array
+   * @throws UnsupportedOperationException if this list is not backed by an 
accessible heap array
+   */
   public long[] getArray() {
     return array;
   }
diff --git 
a/java/fory-core/src/main/java/org/apache/fory/collection/Int8List.java 
b/java/fory-core/src/main/java/org/apache/fory/collection/Int8List.java
index 3927262eb..cf6e4b5c7 100644
--- a/java/fory-core/src/main/java/org/apache/fory/collection/Int8List.java
+++ b/java/fory-core/src/main/java/org/apache/fory/collection/Int8List.java
@@ -145,7 +145,31 @@ public final class Int8List extends AbstractList<Byte> 
implements RandomAccess {
     return true;
   }
 
-  /** Returns the live backing array; elements beyond {@code size()} are 
undefined. */
+  /**
+   * Returns {@code true} if this list is backed by an accessible heap array.
+   *
+   * <p>If this method returns {@code true}, then {@link #getArray()} may be 
safely called to obtain
+   * the underlying storage without incurring a data copy.
+   *
+   * @return {@code true} if this list is backed by a primitive array and is 
not read-only
+   */
+  public boolean hasArray() {
+    return array != null;
+  }
+
+  /**
+   * Returns the underlying heap array that backs this list.
+   *
+   * <p><b>Warning:</b> Users should check {@link #hasArray()} before calling 
this method. If {@code
+   * hasArray()} returns {@code false}, this method will return a copy that 
does not reflect
+   * subsequent mutations.
+   *
+   * <p>Modifying the returned array will directly affect the list, and vice 
versa. Elements beyond
+   * {@link #size()} are undefined.
+   *
+   * @return the backing array
+   * @throws UnsupportedOperationException if this list is not backed by an 
accessible heap array
+   */
   public byte[] getArray() {
     return array;
   }
diff --git 
a/java/fory-core/src/main/java/org/apache/fory/collection/Uint16List.java 
b/java/fory-core/src/main/java/org/apache/fory/collection/Uint16List.java
index 3c0239886..17a5ced92 100644
--- a/java/fory-core/src/main/java/org/apache/fory/collection/Uint16List.java
+++ b/java/fory-core/src/main/java/org/apache/fory/collection/Uint16List.java
@@ -145,7 +145,31 @@ public final class Uint16List extends AbstractList<Uint16> 
implements RandomAcce
     return array[index];
   }
 
-  /** Returns the live backing array; elements beyond {@code size()} are 
undefined. */
+  /**
+   * Returns {@code true} if this list is backed by an accessible heap array.
+   *
+   * <p>If this method returns {@code true}, then {@link #getArray()} may be 
safely called to obtain
+   * the underlying storage without incurring a data copy.
+   *
+   * @return {@code true} if this list is backed by a primitive array and is 
not read-only
+   */
+  public boolean hasArray() {
+    return array != null;
+  }
+
+  /**
+   * Returns the underlying heap array that backs this list.
+   *
+   * <p><b>Warning:</b> Users should check {@link #hasArray()} before calling 
this method. If {@code
+   * hasArray()} returns {@code false}, this method will return a copy that 
does not reflect
+   * subsequent mutations.
+   *
+   * <p>Modifying the returned array will directly affect the list, and vice 
versa. Elements beyond
+   * {@link #size()} are undefined.
+   *
+   * @return the backing array
+   * @throws UnsupportedOperationException if this list is not backed by an 
accessible heap array
+   */
   public short[] getArray() {
     return array;
   }
diff --git 
a/java/fory-core/src/main/java/org/apache/fory/collection/Uint32List.java 
b/java/fory-core/src/main/java/org/apache/fory/collection/Uint32List.java
index 654155aae..7d1e8618e 100644
--- a/java/fory-core/src/main/java/org/apache/fory/collection/Uint32List.java
+++ b/java/fory-core/src/main/java/org/apache/fory/collection/Uint32List.java
@@ -145,7 +145,31 @@ public final class Uint32List extends AbstractList<Uint32> 
implements RandomAcce
     return array[index];
   }
 
-  /** Returns the live backing array; elements beyond {@code size()} are 
undefined. */
+  /**
+   * Returns {@code true} if this list is backed by an accessible heap array.
+   *
+   * <p>If this method returns {@code true}, then {@link #getArray()} may be 
safely called to obtain
+   * the underlying storage without incurring a data copy.
+   *
+   * @return {@code true} if this list is backed by a primitive array and is 
not read-only
+   */
+  public boolean hasArray() {
+    return array != null;
+  }
+
+  /**
+   * Returns the underlying heap array that backs this list.
+   *
+   * <p><b>Warning:</b> Users should check {@link #hasArray()} before calling 
this method. If {@code
+   * hasArray()} returns {@code false}, this method will return a copy that 
does not reflect
+   * subsequent mutations.
+   *
+   * <p>Modifying the returned array will directly affect the list, and vice 
versa. Elements beyond
+   * {@link #size()} are undefined.
+   *
+   * @return the backing array
+   * @throws UnsupportedOperationException if this list is not backed by an 
accessible heap array
+   */
   public int[] getArray() {
     return array;
   }
diff --git 
a/java/fory-core/src/main/java/org/apache/fory/collection/Uint64List.java 
b/java/fory-core/src/main/java/org/apache/fory/collection/Uint64List.java
index 93297f49b..057d82c6b 100644
--- a/java/fory-core/src/main/java/org/apache/fory/collection/Uint64List.java
+++ b/java/fory-core/src/main/java/org/apache/fory/collection/Uint64List.java
@@ -126,7 +126,31 @@ public final class Uint64List extends AbstractList<Uint64> 
implements RandomAcce
     return array[index];
   }
 
-  /** Returns the live backing array; elements beyond {@code size()} are 
undefined. */
+  /**
+   * Returns {@code true} if this list is backed by an accessible heap array.
+   *
+   * <p>If this method returns {@code true}, then {@link #getArray()} may be 
safely called to obtain
+   * the underlying storage without incurring a data copy.
+   *
+   * @return {@code true} if this list is backed by a primitive array and is 
not read-only
+   */
+  public boolean hasArray() {
+    return array != null;
+  }
+
+  /**
+   * Returns the underlying heap array that backs this list.
+   *
+   * <p><b>Warning:</b> Users should check {@link #hasArray()} before calling 
this method. If {@code
+   * hasArray()} returns {@code false}, this method will return a copy that 
does not reflect
+   * subsequent mutations.
+   *
+   * <p>Modifying the returned array will directly affect the list, and vice 
versa. Elements beyond
+   * {@link #size()} are undefined.
+   *
+   * @return the backing array
+   * @throws UnsupportedOperationException if this list is not backed by an 
accessible heap array
+   */
   public long[] getArray() {
     return array;
   }
diff --git 
a/java/fory-core/src/main/java/org/apache/fory/collection/Uint8List.java 
b/java/fory-core/src/main/java/org/apache/fory/collection/Uint8List.java
index 3bce16ebe..ef2b810ab 100644
--- a/java/fory-core/src/main/java/org/apache/fory/collection/Uint8List.java
+++ b/java/fory-core/src/main/java/org/apache/fory/collection/Uint8List.java
@@ -145,7 +145,31 @@ public final class Uint8List extends AbstractList<Uint8> 
implements RandomAccess
     return array[index];
   }
 
-  /** Returns the live backing array; elements beyond {@code size()} are 
undefined. */
+  /**
+   * Returns {@code true} if this list is backed by an accessible heap array.
+   *
+   * <p>If this method returns {@code true}, then {@link #getArray()} may be 
safely called to obtain
+   * the underlying storage without incurring a data copy.
+   *
+   * @return {@code true} if this list is backed by a primitive array and is 
not read-only
+   */
+  public boolean hasArray() {
+    return array != null;
+  }
+
+  /**
+   * Returns the underlying heap array that backs this list.
+   *
+   * <p><b>Warning:</b> Users should check {@link #hasArray()} before calling 
this method. If {@code
+   * hasArray()} returns {@code false}, this method will return a copy that 
does not reflect
+   * subsequent mutations.
+   *
+   * <p>Modifying the returned array will directly affect the list, and vice 
versa. Elements beyond
+   * {@link #size()} are undefined.
+   *
+   * @return the backing array
+   * @throws UnsupportedOperationException if this list is not backed by an 
accessible heap array
+   */
   public byte[] getArray() {
     return array;
   }
diff --git a/java/fory-core/src/main/java/org/apache/fory/meta/FieldTypes.java 
b/java/fory-core/src/main/java/org/apache/fory/meta/FieldTypes.java
index 3f653b378..07753aee2 100644
--- a/java/fory-core/src/main/java/org/apache/fory/meta/FieldTypes.java
+++ b/java/fory-core/src/main/java/org/apache/fory/meta/FieldTypes.java
@@ -32,7 +32,18 @@ import java.lang.reflect.Array;
 import java.lang.reflect.Field;
 import java.util.Objects;
 import org.apache.fory.annotation.ForyField;
+import org.apache.fory.collection.BoolList;
+import org.apache.fory.collection.Float32List;
+import org.apache.fory.collection.Float64List;
+import org.apache.fory.collection.Int16List;
+import org.apache.fory.collection.Int32List;
+import org.apache.fory.collection.Int64List;
+import org.apache.fory.collection.Int8List;
 import org.apache.fory.collection.Tuple2;
+import org.apache.fory.collection.Uint16List;
+import org.apache.fory.collection.Uint32List;
+import org.apache.fory.collection.Uint64List;
+import org.apache.fory.collection.Uint8List;
 import org.apache.fory.logging.Logger;
 import org.apache.fory.logging.LoggerFactory;
 import org.apache.fory.memory.MemoryBuffer;
@@ -157,6 +168,10 @@ public class FieldTypes {
       typeId = Types.UNION;
     }
 
+    if (Types.isPrimitiveArray(typeId & 0xff)) {
+      return new RegisteredFieldType(nullable, trackingRef, typeId);
+    }
+
     if (COLLECTION_TYPE.isSupertypeOf(genericType.getTypeRef())) {
       return new CollectionFieldType(
           typeId,
@@ -484,6 +499,10 @@ public class FieldTypes {
           if (declaredRaw.isArray()) {
             return TypeRef.of(declaredRaw, new TypeExtMeta(typeId, nullable, 
trackingRef));
           }
+          Class<?> listClass = getPrimitiveListClass(internalTypeId);
+          if (listClass != null && listClass.isAssignableFrom(declaredRaw)) {
+            return TypeRef.of(declaredRaw, new TypeExtMeta(typeId, nullable, 
trackingRef));
+          }
         }
         cls = getPrimitiveArrayClass(internalTypeId);
         if (cls != null) {
@@ -580,6 +599,35 @@ public class FieldTypes {
     }
   }
 
+  private static Class<?> getPrimitiveListClass(int typeId) {
+    switch (typeId) {
+      case Types.BOOL_ARRAY:
+        return BoolList.class;
+      case Types.INT8_ARRAY:
+        return Int8List.class;
+      case Types.UINT8_ARRAY:
+        return Uint8List.class;
+      case Types.INT16_ARRAY:
+        return Int16List.class;
+      case Types.UINT16_ARRAY:
+        return Uint16List.class;
+      case Types.INT32_ARRAY:
+        return Int32List.class;
+      case Types.UINT32_ARRAY:
+        return Uint32List.class;
+      case Types.INT64_ARRAY:
+        return Int64List.class;
+      case Types.UINT64_ARRAY:
+        return Uint64List.class;
+      case Types.FLOAT32_ARRAY:
+        return Float32List.class;
+      case Types.FLOAT64_ARRAY:
+        return Float64List.class;
+      default:
+        return null;
+    }
+  }
+
   /**
    * Class for collection field type, which store collection element type 
information. Nested
    * collection/map generics example:
diff --git 
a/java/fory-core/src/main/java/org/apache/fory/resolver/ClassResolver.java 
b/java/fory-core/src/main/java/org/apache/fory/resolver/ClassResolver.java
index e758ebd6f..099433c00 100644
--- a/java/fory-core/src/main/java/org/apache/fory/resolver/ClassResolver.java
+++ b/java/fory-core/src/main/java/org/apache/fory/resolver/ClassResolver.java
@@ -871,6 +871,9 @@ public class ClassResolver extends TypeResolver {
    */
   @Override
   public boolean isMonomorphic(Class<?> clz) {
+    if (TypeUtils.isPrimitiveListClass(clz)) {
+      return true;
+    }
     if (fory.getConfig().isMetaShareEnabled()) {
       // can't create final map/collection type using 
TypeUtils.mapOf(TypeToken<K>,
       // TypeToken<V>)
@@ -893,6 +896,9 @@ public class ClassResolver extends TypeResolver {
   }
 
   public boolean isBuildIn(Descriptor descriptor) {
+    if (TypeUtils.isPrimitiveListClass(descriptor.getRawType())) {
+      return true;
+    }
     return isMonomorphic(descriptor);
   }
 
diff --git 
a/java/fory-core/src/main/java/org/apache/fory/resolver/TypeResolver.java 
b/java/fory-core/src/main/java/org/apache/fory/resolver/TypeResolver.java
index 6e136d225..c973b50b7 100644
--- a/java/fory-core/src/main/java/org/apache/fory/resolver/TypeResolver.java
+++ b/java/fory-core/src/main/java/org/apache/fory/resolver/TypeResolver.java
@@ -992,15 +992,19 @@ public abstract class TypeResolver {
 
   public abstract <T> void setSerializerIfAbsent(Class<T> cls, Serializer<T> 
serializer);
 
-  public final Serializer<?> getSerializerByTypeId(int typeId) {
+  public final ClassInfo getClassInfoByTypeId(int typeId) {
     int internalTypeId = typeId & 0xFF;
     if (Types.isUserDefinedType((byte) internalTypeId)) {
       int userId = typeId >>> 8;
       if (userId != 0) {
-        return requireUserTypeInfoByTypeId(userId).getSerializer();
+        return requireUserTypeInfoByTypeId(userId);
       }
     }
-    return requireInternalTypeInfoByTypeId(internalTypeId).getSerializer();
+    return requireInternalTypeInfoByTypeId(internalTypeId);
+  }
+
+  public final Serializer<?> getSerializerByTypeId(int typeId) {
+    return getClassInfoByTypeId(typeId).getSerializer();
   }
 
   public final ClassInfo nilClassInfo() {
@@ -1144,6 +1148,9 @@ public abstract class TypeResolver {
   }
 
   public final boolean isCollection(Class<?> cls) {
+    if (TypeUtils.isPrimitiveListClass(cls)) {
+      return false;
+    }
     if (Collection.class.isAssignableFrom(cls)) {
       return true;
     }
diff --git 
a/java/fory-core/src/main/java/org/apache/fory/resolver/XtypeResolver.java 
b/java/fory-core/src/main/java/org/apache/fory/resolver/XtypeResolver.java
index 4f8cd30bb..785dd2266 100644
--- a/java/fory-core/src/main/java/org/apache/fory/resolver/XtypeResolver.java
+++ b/java/fory-core/src/main/java/org/apache/fory/resolver/XtypeResolver.java
@@ -561,6 +561,9 @@ public class XtypeResolver extends TypeResolver {
         return true;
       default:
         Class<?> rawType = descriptor.getRawType();
+        if (TypeUtils.isPrimitiveListClass(rawType)) {
+          return true;
+        }
         if (rawType == Object.class) {
           return false;
         }
@@ -583,6 +586,9 @@ public class XtypeResolver extends TypeResolver {
 
   @Override
   public boolean isMonomorphic(Class<?> clz) {
+    if (TypeUtils.isPrimitiveListClass(clz)) {
+      return true;
+    }
     if (clz == Object.class) {
       return false;
     }
@@ -618,6 +624,9 @@ public class XtypeResolver extends TypeResolver {
 
   public boolean isBuildIn(Descriptor descriptor) {
     Class<?> rawType = descriptor.getRawType();
+    if (TypeUtils.isPrimitiveListClass(rawType)) {
+      return true;
+    }
     byte typeIdByte = getInternalTypeId(descriptor);
     if (NonexistentClass.class.isAssignableFrom(rawType)) {
       return false;
diff --git 
a/java/fory-core/src/main/java/org/apache/fory/serializer/Serializers.java 
b/java/fory-core/src/main/java/org/apache/fory/serializer/Serializers.java
index 5f0ff49b9..48654a80d 100644
--- a/java/fory-core/src/main/java/org/apache/fory/serializer/Serializers.java
+++ b/java/fory-core/src/main/java/org/apache/fory/serializer/Serializers.java
@@ -176,6 +176,22 @@ public class Serializers {
     }
   }
 
+  public static <T> void write(MemoryBuffer buffer, Serializer<T> serializer, 
T obj) {
+    if (serializer.isJava) {
+      serializer.write(buffer, obj);
+    } else {
+      serializer.xwrite(buffer, obj);
+    }
+  }
+
+  public static <T> T read(MemoryBuffer buffer, Serializer<T> serializer) {
+    if (serializer.isJava) {
+      return serializer.read(buffer);
+    } else {
+      return serializer.xread(buffer);
+    }
+  }
+
   public abstract static class CrossLanguageCompatibleSerializer<T> extends 
Serializer<T> {
 
     public CrossLanguageCompatibleSerializer(Fory fory, Class<T> cls) {
diff --git 
a/java/fory-core/src/main/java/org/apache/fory/serializer/UnionSerializer.java 
b/java/fory-core/src/main/java/org/apache/fory/serializer/UnionSerializer.java
index da8c38297..c8987e104 100644
--- 
a/java/fory-core/src/main/java/org/apache/fory/serializer/UnionSerializer.java
+++ 
b/java/fory-core/src/main/java/org/apache/fory/serializer/UnionSerializer.java
@@ -21,15 +21,20 @@ package org.apache.fory.serializer;
 
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.HashMap;
+import java.util.Map;
 import java.util.function.BiFunction;
 import org.apache.fory.Fory;
+import org.apache.fory.collection.LongMap;
 import org.apache.fory.logging.Logger;
 import org.apache.fory.logging.LoggerFactory;
 import org.apache.fory.memory.MemoryBuffer;
 import org.apache.fory.resolver.ClassInfo;
 import org.apache.fory.resolver.RefResolver;
 import org.apache.fory.resolver.TypeResolver;
-import org.apache.fory.resolver.XtypeResolver;
 import org.apache.fory.type.Types;
 import org.apache.fory.type.union.Union;
 import org.apache.fory.type.union.Union2;
@@ -37,6 +42,7 @@ import org.apache.fory.type.union.Union3;
 import org.apache.fory.type.union.Union4;
 import org.apache.fory.type.union.Union5;
 import org.apache.fory.type.union.Union6;
+import org.apache.fory.util.Preconditions;
 
 /**
  * Serializer for {@link Union} and its subclasses ({@link Union2}, {@link 
Union3}, {@link Union4},
@@ -53,11 +59,11 @@ import org.apache.fory.type.union.Union6;
  * deserialization, not from the serialized data. This allows cross-language 
interoperability with
  * union types in other languages like C++'s std::variant, Rust's enum, or 
Python's typing.Union.
  */
+@SuppressWarnings({"rawtypes", "unchecked"})
 public class UnionSerializer extends Serializer<Union> {
   private static final Logger LOG = 
LoggerFactory.getLogger(UnionSerializer.class);
 
   /** Array of factories for creating Union instances by type tag. */
-  @SuppressWarnings("unchecked")
   private static final BiFunction<Integer, Object, Union>[] FACTORIES =
       new BiFunction[] {
         (BiFunction<Integer, Object, Union>) Union::new,
@@ -69,8 +75,11 @@ public class UnionSerializer extends Serializer<Union> {
       };
 
   private final BiFunction<Integer, Object, Union> factory;
+  private final Map<Integer, Class<?>> caseValueTypes;
+  private final LongMap<ClassInfo> finalCaseClassInfo;
+  private boolean finalCaseSerializersResolved;
+  private final TypeResolver resolver;
 
-  @SuppressWarnings("unchecked")
   public UnionSerializer(Fory fory, Class<? extends Union> cls) {
     super(fory, (Class<Union>) cls);
     int typeIndex = getTypeIndex(cls);
@@ -79,6 +88,9 @@ public class UnionSerializer extends Serializer<Union> {
     } else {
       this.factory = createFactory(cls);
     }
+    finalCaseClassInfo = new LongMap<>();
+    this.caseValueTypes = resolveCaseValueTypes(cls);
+    resolver = fory.getTypeResolver();
   }
 
   private static int getTypeIndex(Class<? extends Union> cls) {
@@ -107,7 +119,7 @@ public class UnionSerializer extends Serializer<Union> {
       MethodHandle handle = MethodHandles.lookup().unreflectConstructor(ctor);
       return (index, value) -> {
         try {
-          return (Union) handle.invoke(index.intValue(), value);
+          return (Union) handle.invoke(index, value);
         } catch (Throwable t) {
           throw new IllegalStateException("Failed to construct union type " + 
cls.getName(), t);
         }
@@ -135,13 +147,17 @@ public class UnionSerializer extends Serializer<Union> {
     int valueTypeId = union.getValueTypeId();
     if (valueTypeId == Types.UNKNOWN) {
       if (value != null) {
-        fory.xwriteRef(buffer, value);
+        if (fory.isCrossLanguage()) {
+          fory.xwriteRef(buffer, value);
+        } else {
+          fory.writeRef(buffer, value);
+        }
       } else {
         buffer.writeByte(Fory.NULL_FLAG);
       }
       return;
     }
-    writeCaseValue(buffer, value, valueTypeId);
+    writeCaseValue(buffer, value, valueTypeId, index);
   }
 
   @Override
@@ -152,8 +168,22 @@ public class UnionSerializer extends Serializer<Union> {
   @Override
   public Union xread(MemoryBuffer buffer) {
     int index = buffer.readVarUint32();
-    Object value = fory.xreadRef(buffer);
-    return factory.apply(index, value);
+    Object caseValue;
+    int nextReadRefId = refResolver.tryPreserveRefId(buffer);
+    if (nextReadRefId >= Fory.NOT_NULL_VALUE_FLAG) {
+      // ref value or not-null value
+      ClassInfo declared = getFinalCaseClassInfo(index);
+      ClassInfo readClassInfo = resolver.readClassInfo(buffer, declared);
+      if (declared != null) {
+        caseValue = Serializers.read(buffer, declared.getSerializer());
+      } else {
+        caseValue = Serializers.read(buffer, readClassInfo.getSerializer());
+      }
+      refResolver.setReadObject(nextReadRefId, caseValue);
+    } else {
+      caseValue = refResolver.getReadObject();
+    }
+    return factory.apply(index, caseValue);
   }
 
   @Override
@@ -166,66 +196,40 @@ public class UnionSerializer extends Serializer<Union> {
     return factory.apply(union.getIndex(), copiedValue);
   }
 
-  private void writeCaseValue(MemoryBuffer buffer, Object value, int typeId) {
-    Serializer serializer = null;
-    if (value != null) {
-      serializer = getSerializer(typeId, value);
+  private void writeCaseValue(MemoryBuffer buffer, Object value, int typeId, 
int caseId) {
+    byte internalTypeId = (byte) (typeId & 0xff);
+    boolean primitiveArray = Types.isPrimitiveArray(internalTypeId);
+    Serializer serializer;
+    ClassInfo classInfo;
+    if (value == null) {
+      buffer.writeByte(Fory.NULL_FLAG);
+      return;
     }
+    classInfo = getFinalCaseClassInfo(caseId);
+    if (classInfo == null) {
+      Preconditions.checkArgument(!primitiveArray);
+      if (!Types.isUserDefinedType(internalTypeId)) {
+        classInfo = resolver.getClassInfoByTypeId(internalTypeId);
+      } else {
+        classInfo = resolver.getClassInfo(value.getClass());
+      }
+    }
+    Preconditions.checkArgument(classInfo != null);
+    serializer = classInfo.getSerializer();
     RefResolver refResolver = fory.getRefResolver();
     if (serializer != null && serializer.needToWriteRef()) {
       if (refResolver.writeRefOrNull(buffer, value)) {
         return;
       }
     } else {
-      if (value == null) {
-        buffer.writeByte(Fory.NULL_FLAG);
-        return;
-      }
       buffer.writeByte(Fory.NOT_NULL_VALUE_FLAG);
     }
-    writeTypeInfo(buffer, typeId, value);
-    writeValue(buffer, value, typeId, serializer);
-  }
-
-  private Serializer getSerializer(int typeId, Object value) {
-    int internalTypeId = typeId & 0xff;
-    if (isPrimitiveType(internalTypeId)) {
-      return null;
-    }
-    ClassInfo classInfo = getClassInfo(typeId, value);
-    return classInfo == null ? null : classInfo.getSerializer();
-  }
-
-  private void writeTypeInfo(MemoryBuffer buffer, int typeId, Object value) {
-    ClassInfo classInfo = getClassInfo(typeId, value);
-    if (classInfo == null) {
+    if (!Types.isUserDefinedType(internalTypeId)) {
       buffer.writeVarUint32Small7(typeId);
-      return;
-    }
-    fory.getTypeResolver().writeClassInfo(buffer, classInfo);
-  }
-
-  private ClassInfo getClassInfo(int typeId, Object value) {
-    TypeResolver resolver = fory.getTypeResolver();
-    int internalTypeId = typeId & 0xff;
-    if (typeId >= 256 && resolver instanceof XtypeResolver) {
-      ClassInfo classInfo = ((XtypeResolver) resolver).getUserTypeInfo(typeId 
>>> 8);
-      if (classInfo != null) {
-        if ((classInfo.getTypeId() & 0xff) == internalTypeId) {
-          return classInfo;
-        }
-      }
-    }
-    if (isNamedType(internalTypeId)) {
-      return resolver.getClassInfo(value.getClass());
-    }
-    if (resolver instanceof XtypeResolver) {
-      ClassInfo classInfo = ((XtypeResolver) resolver).getXtypeInfo(typeId);
-      if (classInfo != null) {
-        return classInfo;
-      }
+    } else {
+      resolver.writeClassInfo(buffer, classInfo);
     }
-    return resolver.getClassInfo(value.getClass());
+    writeValue(buffer, value, typeId, serializer);
   }
 
   private void writeValue(MemoryBuffer buffer, Object value, int typeId, 
Serializer serializer) {
@@ -284,45 +288,116 @@ public class UnionSerializer extends Serializer<Union> {
         break;
     }
     if (serializer != null) {
-      serializer.xwrite(buffer, value);
+      Serializers.write(buffer, serializer, value);
       return;
     }
     throw new IllegalStateException("Missing serializer for union type id " + 
typeId);
   }
 
-  private static boolean isNamedType(int internalTypeId) {
-    return internalTypeId == Types.NAMED_ENUM
-        || internalTypeId == Types.NAMED_STRUCT
-        || internalTypeId == Types.NAMED_EXT
-        || internalTypeId == Types.NAMED_UNION
-        || internalTypeId == Types.NAMED_COMPATIBLE_STRUCT;
+  private ClassInfo getFinalCaseClassInfo(int caseId) {
+    if (!finalCaseSerializersResolved) {
+      resolveFinalCaseClassInfo();
+      finalCaseSerializersResolved = true;
+    }
+    return finalCaseClassInfo.get(caseId);
   }
 
-  private static boolean isPrimitiveType(int internalTypeId) {
-    switch (internalTypeId) {
-      case Types.BOOL:
-      case Types.INT8:
-      case Types.INT16:
-      case Types.INT32:
-      case Types.VARINT32:
-      case Types.INT64:
-      case Types.VARINT64:
-      case Types.TAGGED_INT64:
-      case Types.UINT8:
-      case Types.UINT16:
-      case Types.UINT32:
-      case Types.VAR_UINT32:
-      case Types.UINT64:
-      case Types.VAR_UINT64:
-      case Types.TAGGED_UINT64:
-      case Types.FLOAT16:
-      case Types.FLOAT32:
-      case Types.FLOAT64:
-      case Types.STRING:
-      case Types.BINARY:
-        return true;
-      default:
-        return false;
+  private void resolveFinalCaseClassInfo() {
+    for (Map.Entry<Integer, Class<?>> entry : caseValueTypes.entrySet()) {
+      Class<?> expectedType = entry.getValue();
+      if (!isFinalCaseType(expectedType)) {
+        continue;
+      }
+      if (expectedType.isPrimitive()) {
+        continue;
+      }
+      ClassInfo classInfo = fory.getTypeResolver().getClassInfo(expectedType);
+      finalCaseClassInfo.put(entry.getKey(), classInfo);
+    }
+  }
+
+  private static boolean isFinalCaseType(Class<?> expectedType) {
+    return expectedType.isArray() || 
Modifier.isFinal(expectedType.getModifiers());
+  }
+
+  private Map<Integer, Class<?>> resolveCaseValueTypes(Class<? extends Union> 
unionClass) {
+    Map<Integer, Class<?>> mapping = new HashMap<>();
+    Class<? extends Enum<?>> caseEnum = null;
+    Field idField = null;
+    for (Class<?> nested : unionClass.getDeclaredClasses()) {
+      if (nested.isEnum() && nested.getSimpleName().endsWith("Case")) {
+        @SuppressWarnings("unchecked")
+        Class<? extends Enum<?>> enumClass = (Class<? extends Enum<?>>) nested;
+        try {
+          Field field = enumClass.getDeclaredField("id");
+          if (field.getType() == int.class) {
+            caseEnum = enumClass;
+            idField = field;
+            idField.setAccessible(true);
+            break;
+          }
+        } catch (NoSuchFieldException ignored) {
+          // try next enum
+        }
+      }
+    }
+    if (caseEnum == null) {
+      return mapping;
+    }
+    for (Enum<?> constant : caseEnum.getEnumConstants()) {
+      int caseId;
+      try {
+        caseId = (int) idField.get(constant);
+      } catch (IllegalAccessException e) {
+        continue;
+      }
+      String suffix = toPascalCase(constant.name());
+      Class<?> expected = findCaseValueType(unionClass, suffix);
+      if (expected != null) {
+        mapping.put(caseId, expected);
+      }
+    }
+    return mapping;
+  }
+
+  private static Class<?> findCaseValueType(Class<? extends Union> unionClass, 
String suffix) {
+    String setterName = "set" + suffix;
+    for (Method method : unionClass.getMethods()) {
+      if (!Modifier.isPublic(method.getModifiers())) {
+        continue;
+      }
+      if (method.getName().equals(setterName) && method.getParameterCount() == 
1) {
+        return method.getParameterTypes()[0];
+      }
+    }
+    String getterName = "get" + suffix;
+    for (Method method : unionClass.getMethods()) {
+      if (!Modifier.isPublic(method.getModifiers())) {
+        continue;
+      }
+      if (method.getName().equals(getterName) && method.getParameterCount() == 
0) {
+        Class<?> returnType = method.getReturnType();
+        if (returnType != void.class) {
+          return returnType;
+        }
+      }
+    }
+    return null;
+  }
+
+  private static String toPascalCase(String upperSnake) {
+    StringBuilder builder = new StringBuilder();
+    String[] parts = upperSnake.split("_");
+    for (String part : parts) {
+      if (part.isEmpty()) {
+        continue;
+      }
+      String lower = part.toLowerCase();
+      builder.append(Character.toUpperCase(lower.charAt(0)));
+      if (lower.length() > 1) {
+        builder.append(lower.substring(1));
+      }
     }
+    return builder.toString();
   }
 }
diff --git 
a/java/fory-core/src/main/java/org/apache/fory/serializer/struct/Fingerprint.java
 
b/java/fory-core/src/main/java/org/apache/fory/serializer/struct/Fingerprint.java
index 75d2c9e11..d31f62295 100644
--- 
a/java/fory-core/src/main/java/org/apache/fory/serializer/struct/Fingerprint.java
+++ 
b/java/fory-core/src/main/java/org/apache/fory/serializer/struct/Fingerprint.java
@@ -23,6 +23,17 @@ import java.util.ArrayList;
 import java.util.List;
 import org.apache.fory.Fory;
 import org.apache.fory.annotation.ForyField;
+import org.apache.fory.collection.BoolList;
+import org.apache.fory.collection.Float32List;
+import org.apache.fory.collection.Float64List;
+import org.apache.fory.collection.Int16List;
+import org.apache.fory.collection.Int32List;
+import org.apache.fory.collection.Int64List;
+import org.apache.fory.collection.Int8List;
+import org.apache.fory.collection.Uint16List;
+import org.apache.fory.collection.Uint32List;
+import org.apache.fory.collection.Uint64List;
+import org.apache.fory.collection.Uint8List;
 import org.apache.fory.logging.Logger;
 import org.apache.fory.logging.LoggerFactory;
 import org.apache.fory.reflect.ReflectionUtils;
@@ -144,6 +155,10 @@ public class Fingerprint {
 
   private static int getTypeId(Fory fory, Descriptor descriptor) {
     Class<?> cls = descriptor.getTypeRef().getRawType();
+    Integer primitiveListTypeId = getPrimitiveListTypeId(cls);
+    if (primitiveListTypeId != null) {
+      return primitiveListTypeId;
+    }
     TypeResolver resolver = fory.getTypeResolver();
     if (resolver.isSet(cls)) {
       return Types.SET;
@@ -169,4 +184,41 @@ public class Fingerprint {
       return typeId;
     }
   }
+
+  private static Integer getPrimitiveListTypeId(Class<?> cls) {
+    if (cls == BoolList.class) {
+      return Types.BOOL_ARRAY;
+    }
+    if (cls == Int8List.class) {
+      return Types.INT8_ARRAY;
+    }
+    if (cls == Int16List.class) {
+      return Types.INT16_ARRAY;
+    }
+    if (cls == Int32List.class) {
+      return Types.INT32_ARRAY;
+    }
+    if (cls == Int64List.class) {
+      return Types.INT64_ARRAY;
+    }
+    if (cls == Uint8List.class) {
+      return Types.UINT8_ARRAY;
+    }
+    if (cls == Uint16List.class) {
+      return Types.UINT16_ARRAY;
+    }
+    if (cls == Uint32List.class) {
+      return Types.UINT32_ARRAY;
+    }
+    if (cls == Uint64List.class) {
+      return Types.UINT64_ARRAY;
+    }
+    if (cls == Float32List.class) {
+      return Types.FLOAT32_ARRAY;
+    }
+    if (cls == Float64List.class) {
+      return Types.FLOAT64_ARRAY;
+    }
+    return null;
+  }
 }
diff --git a/java/fory-core/src/main/java/org/apache/fory/type/TypeUtils.java 
b/java/fory-core/src/main/java/org/apache/fory/type/TypeUtils.java
index 5859e4c62..a8820435f 100644
--- a/java/fory-core/src/main/java/org/apache/fory/type/TypeUtils.java
+++ b/java/fory-core/src/main/java/org/apache/fory/type/TypeUtils.java
@@ -70,8 +70,19 @@ import java.util.TimeZone;
 import java.util.WeakHashMap;
 import java.util.stream.Collectors;
 import org.apache.fory.annotation.Ref;
+import org.apache.fory.collection.BoolList;
+import org.apache.fory.collection.Float32List;
+import org.apache.fory.collection.Float64List;
 import org.apache.fory.collection.IdentityMap;
+import org.apache.fory.collection.Int16List;
+import org.apache.fory.collection.Int32List;
+import org.apache.fory.collection.Int64List;
+import org.apache.fory.collection.Int8List;
 import org.apache.fory.collection.Tuple2;
+import org.apache.fory.collection.Uint16List;
+import org.apache.fory.collection.Uint32List;
+import org.apache.fory.collection.Uint64List;
+import org.apache.fory.collection.Uint8List;
 import org.apache.fory.meta.TypeExtMeta;
 import org.apache.fory.reflect.ReflectionUtils;
 import org.apache.fory.reflect.TypeParameter;
@@ -655,9 +666,26 @@ public class TypeUtils {
   }
 
   public static boolean isCollection(Class<?> cls) {
+    if (isPrimitiveListClass(cls)) {
+      return false;
+    }
     return cls == ArrayList.class || Collection.class.isAssignableFrom(cls);
   }
 
+  public static boolean isPrimitiveListClass(Class<?> cls) {
+    return cls == BoolList.class
+        || cls == Int8List.class
+        || cls == Int16List.class
+        || cls == Int32List.class
+        || cls == Int64List.class
+        || cls == Uint8List.class
+        || cls == Uint16List.class
+        || cls == Uint32List.class
+        || cls == Uint64List.class
+        || cls == Float32List.class
+        || cls == Float64List.class;
+  }
+
   public static boolean isMap(Class<?> cls) {
     if (cls == NonexistentClass.NonexistentMetaShared.class) {
       return false;
diff --git 
a/java/fory-core/src/test/java/org/apache/fory/serializer/PrimitiveSerializersTest.java
 
b/java/fory-core/src/test/java/org/apache/fory/serializer/PrimitiveSerializersTest.java
index 5ef68ba19..c662eaf6c 100644
--- 
a/java/fory-core/src/test/java/org/apache/fory/serializer/PrimitiveSerializersTest.java
+++ 
b/java/fory-core/src/test/java/org/apache/fory/serializer/PrimitiveSerializersTest.java
@@ -25,10 +25,25 @@ import lombok.AllArgsConstructor;
 import lombok.Data;
 import org.apache.fory.Fory;
 import org.apache.fory.ForyTestBase;
+import org.apache.fory.annotation.Int8ArrayType;
+import org.apache.fory.annotation.Uint16ArrayType;
+import org.apache.fory.annotation.Uint32ArrayType;
+import org.apache.fory.annotation.Uint64ArrayType;
+import org.apache.fory.annotation.Uint8ArrayType;
+import org.apache.fory.collection.Int16List;
+import org.apache.fory.collection.Int32List;
+import org.apache.fory.collection.Int64List;
+import org.apache.fory.collection.Int8List;
+import org.apache.fory.collection.Uint16List;
+import org.apache.fory.collection.Uint32List;
+import org.apache.fory.collection.Uint64List;
+import org.apache.fory.collection.Uint8List;
+import org.apache.fory.config.CompatibleMode;
 import org.apache.fory.config.ForyBuilder;
 import org.apache.fory.config.Language;
 import org.apache.fory.config.LongEncoding;
 import org.apache.fory.memory.MemoryBuffer;
+import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 
 public class PrimitiveSerializersTest extends ForyTestBase {
@@ -143,4 +158,112 @@ public class PrimitiveSerializersTest extends 
ForyTestBase {
             Double.MIN_VALUE);
     copyCheck(fory, struct);
   }
+
+  @DataProvider(name = "compatibleMode")
+  public static Object[][] compatibleModeProvider() {
+    return new Object[][] {{false}, {true}};
+  }
+
+  public static class PrimitiveArrayStruct {
+    @Int8ArrayType public byte[] int8Values;
+    public short[] int16Values;
+    public int[] int32Values;
+    public long[] int64Values;
+    @Uint8ArrayType public byte[] uint8Values;
+    @Uint16ArrayType public short[] uint16Values;
+    @Uint32ArrayType public int[] uint32Values;
+    @Uint64ArrayType public long[] uint64Values;
+  }
+
+  public static class PrimitiveListStruct {
+    public Int8List int8Values;
+    public Int16List int16Values;
+    public Int32List int32Values;
+    public Int64List int64Values;
+    public Uint8List uint8Values;
+    public Uint16List uint16Values;
+    public Uint32List uint32Values;
+    public Uint64List uint64Values;
+  }
+
+  @Test(dataProvider = "compatibleMode")
+  public void testPrimitiveArrayListRoundTrip(boolean compatible) {
+    CompatibleMode mode = compatible ? CompatibleMode.COMPATIBLE : 
CompatibleMode.SCHEMA_CONSISTENT;
+    Fory arrayFory =
+        Fory.builder()
+            .withLanguage(Language.XLANG)
+            .withCompatibleMode(mode)
+            .requireClassRegistration(true)
+            .build();
+    Fory listFory =
+        Fory.builder()
+            .withLanguage(Language.XLANG)
+            .withCompatibleMode(mode)
+            .requireClassRegistration(true)
+            .build();
+
+    arrayFory.register(PrimitiveArrayStruct.class, 1001);
+    listFory.register(PrimitiveListStruct.class, 1001);
+
+    PrimitiveArrayStruct arrayStruct = buildPrimitiveArrayStruct();
+    PrimitiveListStruct listStruct = buildPrimitiveListStruct(arrayStruct);
+
+    PrimitiveListStruct listRoundTrip =
+        listFory.deserialize(arrayFory.serialize(arrayStruct), 
PrimitiveListStruct.class);
+    assertListEqualsArray(listRoundTrip, arrayStruct);
+
+    PrimitiveArrayStruct arrayRoundTrip =
+        arrayFory.deserialize(listFory.serialize(listStruct), 
PrimitiveArrayStruct.class);
+    assertArrayEqualsList(arrayRoundTrip, listStruct);
+  }
+
+  private PrimitiveArrayStruct buildPrimitiveArrayStruct() {
+    PrimitiveArrayStruct struct = new PrimitiveArrayStruct();
+    struct.int8Values = new byte[] {1, -2, 3};
+    struct.int16Values = new short[] {100, -200, 300};
+    struct.int32Values = new int[] {1000, -2000, 3000};
+    struct.int64Values = new long[] {10000L, -20000L, 30000L};
+    struct.uint8Values = new byte[] {(byte) 200, (byte) 250};
+    struct.uint16Values = new short[] {(short) 50000, (short) 60000};
+    struct.uint32Values = new int[] {2000000000, 2100000000};
+    struct.uint64Values = new long[] {9000000000L, 12000000000L};
+    return struct;
+  }
+
+  private PrimitiveListStruct buildPrimitiveListStruct(PrimitiveArrayStruct 
arrays) {
+    PrimitiveListStruct struct = new PrimitiveListStruct();
+    struct.int8Values = new Int8List(arrays.int8Values);
+    struct.int16Values = new Int16List(arrays.int16Values);
+    struct.int32Values = new Int32List(arrays.int32Values);
+    struct.int64Values = new Int64List(arrays.int64Values);
+    struct.uint8Values = new Uint8List(arrays.uint8Values);
+    struct.uint16Values = new Uint16List(arrays.uint16Values);
+    struct.uint32Values = new Uint32List(arrays.uint32Values);
+    struct.uint64Values = new Uint64List(arrays.uint64Values);
+    return struct;
+  }
+
+  private void assertListEqualsArray(PrimitiveListStruct list, 
PrimitiveArrayStruct arrays) {
+    assertNotNull(list);
+    assertTrue(java.util.Arrays.equals(list.int8Values.copyArray(), 
arrays.int8Values));
+    assertTrue(java.util.Arrays.equals(list.int16Values.copyArray(), 
arrays.int16Values));
+    assertTrue(java.util.Arrays.equals(list.int32Values.copyArray(), 
arrays.int32Values));
+    assertTrue(java.util.Arrays.equals(list.int64Values.copyArray(), 
arrays.int64Values));
+    assertTrue(java.util.Arrays.equals(list.uint8Values.copyArray(), 
arrays.uint8Values));
+    assertTrue(java.util.Arrays.equals(list.uint16Values.copyArray(), 
arrays.uint16Values));
+    assertTrue(java.util.Arrays.equals(list.uint32Values.copyArray(), 
arrays.uint32Values));
+    assertTrue(java.util.Arrays.equals(list.uint64Values.copyArray(), 
arrays.uint64Values));
+  }
+
+  private void assertArrayEqualsList(PrimitiveArrayStruct arrays, 
PrimitiveListStruct list) {
+    assertNotNull(arrays);
+    assertTrue(java.util.Arrays.equals(arrays.int8Values, 
list.int8Values.copyArray()));
+    assertTrue(java.util.Arrays.equals(arrays.int16Values, 
list.int16Values.copyArray()));
+    assertTrue(java.util.Arrays.equals(arrays.int32Values, 
list.int32Values.copyArray()));
+    assertTrue(java.util.Arrays.equals(arrays.int64Values, 
list.int64Values.copyArray()));
+    assertTrue(java.util.Arrays.equals(arrays.uint8Values, 
list.uint8Values.copyArray()));
+    assertTrue(java.util.Arrays.equals(arrays.uint16Values, 
list.uint16Values.copyArray()));
+    assertTrue(java.util.Arrays.equals(arrays.uint32Values, 
list.uint32Values.copyArray()));
+    assertTrue(java.util.Arrays.equals(arrays.uint64Values, 
list.uint64Values.copyArray()));
+  }
 }


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


Reply via email to