Skip to content

Conversation

@chaokunyang
Copy link
Collaborator

@chaokunyang chaokunyang commented Jan 15, 2026

Why?

Fory needs streaming-friendly shared type meta so readers can deserialize without seeking. The current work also unifies native/xlang type IDs and removes legacy paths that were causing inconsistent type resolution and CI failures across languages.

What does this PR do?

  • Switch shared type meta to the streaming wire format (inline TypeDef bytes with index marker) and remove legacy meta-offset handling.
  • Unify native and xlang type ID handling in Java resolvers, simplify dispatch paths, and remove outdated compatibility branches.
  • Add registerSerializerAndType API for explicit type+serializer registration flow.
  • Fix Go skip path to consume streaming shared type meta in compatible struct skipping and add a regression test.
  • Keep resolver fast paths by inlining class-info reads and avoiding redundant serializer creation.

Related issues

Closes #3157
Closes #3119

#2609 #2818

Does this PR introduce any user-facing change?

  • Does this PR introduce any public API change?
  • Does this PR introduce any binary protocol compatibility change?

Benchmark

Not run.

@chaokunyang chaokunyang force-pushed the implement_stream_class_meta branch from 365c79f to 72817de Compare January 15, 2026 13:21
@chaokunyang chaokunyang force-pushed the implement_stream_class_meta branch from 08798d4 to 4c1b726 Compare January 16, 2026 19:35
@chaokunyang chaokunyang force-pushed the implement_stream_class_meta branch from 4c1b726 to 6a1d48f Compare January 17, 2026 01:13
- Override buildDecodeExpression() to include readLayerClassMeta() call
  to maintain consistency with interpreter-mode MetaSharedLayerSerializer
- Fix fallback serializer class from ObjectSerializer to MetaSharedLayerSerializer
  since ObjectSerializer is not compatible with MetaSharedLayerSerializerBase
- Add static helper method readLayerClassMeta() for generated code to call
…ializer

The read() method now properly handles schema evolution when:
- Sender has class layers that receiver doesn't have (skip sender's data)
- Receiver has class layers that sender doesn't have (call readObjectNoData)

Previously, the code would cause ArrayIndexOutOfBoundsException or data
corruption when sender had parent classes that don't exist in receiver.

Changes:
- Rewrite read loop to properly match sender and receiver layers
- Add skipUnknownLayerData() to skip data for sender-only layers
- Handle remaining receiver-only layers at the end
Add full support for schema evolution when sender has class layers that
receiver doesn't have. This includes:

1. LayerReadContext class to track ClassDefs during deserialization:
   - Maintains list of ClassDefs in stream order
   - Caches skip serializers for reuse
   - Supports both new ClassDefs and references to previously seen ones

2. readAndTrackLayerMeta() to read and track layer meta:
   - Handles new ClassDefs (reads inline and tracks)
   - Handles references (looks up from tracked list)
   - Returns the ClassDef for the layer

3. trackLayerMetaFromSerializer() to track ClassDefs from matched layers:
   - Peeks at buffer to track ClassDefs without consuming
   - Allows matched layers to contribute to tracking
   - Enables later unknown layers to reference earlier ClassDefs

4. skipUnknownLayerData() enhanced with context:
   - Uses tracked ClassDefs for references
   - Creates skip serializer from ClassDef
   - Properly advances buffer position

5. MetaSharedLayerSerializer.skipFields() method:
   - Skips all field types: buildIn, container, other
   - Uses FieldSkipper for basic types
   - Uses binding.readField() for complex types
…alizer

The key insight is that different senders may have different ClassDefs
for the same class layer (schema evolution). The serializer must be
created based on the actual ClassDef from the stream, not the receiver's
expected schema.

Changes:
1. ObjectStreamSerializer now reads layer ClassDef before calling serializer
2. Creates/caches serializers based on the actual ClassDef from stream
3. Calls readFieldsOnly() instead of readAndSetFields() to avoid double-read
4. MetaSharedLayerSerializer.readFieldsOnly() reads fields without meta
5. Removed trackLayerMetaFromSerializer() - no longer needed
6. Simplified LayerReadContext to use single getOrCreateSerializer()
@chaokunyang chaokunyang changed the title feat(xlang/java): streaming read/write type info feat(xlang/java): refactor java native serialization type system and streaming read/write type info for xlang Jan 19, 2026
@chaokunyang chaokunyang changed the title feat(xlang/java): refactor java native serialization type system and streaming read/write type info for xlang feat(xlang/java): refactor java native serialization type system and streaming type info for xlang Jan 19, 2026
@chaokunyang chaokunyang force-pushed the implement_stream_class_meta branch from f07323a to aee8b30 Compare January 19, 2026 07:25
@chaokunyang chaokunyang merged commit 47a73a1 into apache:main Jan 19, 2026
59 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Java] refactor java serialization type system [Xlang] Use stream mode for shared type meta

2 participants