Skip to content

feat(java): add deserialize overloads that take a TypeRef (#3946) - #4163

Open
Swatantra-66 wants to merge 1 commit into
apache:mainfrom
Swatantra-66:feat/add-typeref-deserialize-overloads
Open

Swatantra-66 wants to merge 1 commit into
apache:mainfrom
Swatantra-66:feat/add-typeref-deserialize-overloads

Conversation

@Swatantra-66

@Swatantra-66 Swatantra-66 commented Oct 10, 2026 •

Copy link
Copy Markdown
Contributor

Why?

ForyJson has fromJson methods that accept a TypeRef for cases when the root type is generic (e.g. List<T>, Map<K, V>). However, core Fory previously only provided deserialize overloads accepting Class<T>.

Because Java type erasure strips generic type arguments at runtime from Class, deserializing into generic root collections or maps lost element and key/value type information. Users were unable to deserialize directly into generic root types without attempting low-level, internal TypeResolver manipulations.

What does this PR do?

Adds TypeRef<T> deserialize overloads across BaseFory, Fory, ThreadLocalFory, ThreadPoolFory, and BlockedStreamUtils:

  1. API Declarations (BaseFory):

    • <T> T deserialize(byte[] bytes, TypeRef<T> typeRef)
    • <T> T deserialize(MemoryBuffer buffer, TypeRef<T> typeRef)
    • <T> T deserialize(ForyInputStream inputStream, TypeRef<T> typeRef)
    • <T> T deserialize(ForyReadableChannel channel, TypeRef<T> typeRef)
  2. Core Implementation (Fory):

    • Implemented null-checked overloads (Preconditions.checkNotNull(typeRef, "typeRef must not be null")).
    • Unified deserializeByType into a clean helper accepting GenericType and raw Class<?>, eliminating duplicate code. Pushes typeResolver.buildGenericType(typeRef) to readContext.getGenerics(), preserving root generic parameter metadata (e.g. element type for CollectionLikeSerializer, key/value types for MapLikeSerializer).
  3. Thread-Safe Runtimes:

    • ThreadLocalFory: delegates all 4 overloads to currentFory().deserialize(..., typeRef).
    • ThreadPoolFory: delegates all 4 overloads with thread pool acquire() / release().
  4. Streaming Helper (BlockedStreamUtils):

    • Added deserialize(Fory, InputStream, TypeRef<T>) and deserialize(Fory, ReadableByteChannel, TypeRef<T>).
  5. Comprehensive Tests:

    • ForyTest.java: Added testDeserializeWithTypeRef testing root List<String>, nested Map<String, List<Integer>>, concrete objects via TypeRef.of(...), byte arrays, memory buffers, input streams, channels, and null checks.
    • ThreadSafeForyTest.java: Added testSerializeDeserializeWithTypeRef validating both ThreadLocalFory and ThreadPoolFory.
    • StreamTest.java: Added TypeRef tests for testStream and testReadableChannel.
    • BlockedStreamUtilsTest.java: Added stream and channel deserialization tests with TypeRef.

Related issues

Closes #3946

AI Contribution Checklist

  • Substantial AI assistance was used in this PR: no

Does this PR introduce any user-facing change?

  • Does this PR introduce any public API change? Adds deserialize overloads taking TypeRef<T>.
  • Does this PR introduce any binary protocol compatibility change? No.

Benchmark

No performance impact on existing Class<T> paths. The unified deserializeByType helper avoids duplicate code and overhead.

@Swatantra-66
Swatantra-66 force-pushed the feat/add-typeref-deserialize-overloads branch 2 times, most recently from 983191f to b38e79d Compare October 10, 2026 12:03
@ayush00git
ayush00git self-requested a review October 10, 2026 17:14
checkHeaderBitmapWithoutOutOfBand(bitmap);
}
readContext.prepare(buffer, null, false);
try {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i see a lot of issues in this PR, java/fory-core/src/main/java/org/apache/fory/Fory.java. The root reader now declares element types that the root writer never declared. your tests even not reach the path you changed.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot for the review and catching this, @ayush00git!

  1. Root element types: Because fory.serialize(obj) has no generic context at the root level, the writer emits dynamic element headers/type tags. By pushing buildGenericType(typeRef) into readContext.getGenerics(), the reader was incorrectly expecting monomorphic elements without type headers on the wire. I have updated all deserialize(..., TypeRef<T>) overloads to delegate cleanly to (Class<T>) typeRef.getRawType(), avoiding wire protocol desynchronization while maintaining compile-time type safety for callers.
  2. Test coverage: Arrays.asList() delegates to ArraysAsListSerializer (Object[]), bypassing CollectionLikeSerializer.readElements(). I've updated the tests to use concrete ArrayList, LinkedList, HashSet, HashMap, and nested generic structures, verifying that the actual collection serializers are exercised.

Pushed the updated commit!

@Swatantra-66
Swatantra-66 force-pushed the feat/add-typeref-deserialize-overloads branch from b38e79d to 1b822a9 Compare October 10, 2026 20:57
Add TypeRef<T> deserialize overloads across BaseFory, Fory, ThreadLocalFory, ThreadPoolFory, and BlockedStreamUtils to support explicitly deserializing into generic root types like List<T> or Map<K, V>.

Closes apache#3946.

Signed-off-by: Swatantra Yadav <maverickswatantra@gmail.com>
@Swatantra-66
Swatantra-66 force-pushed the feat/add-typeref-deserialize-overloads branch from 1b822a9 to 81855f0 Compare October 10, 2026 21:02

This branch has not been deployed

No deployments
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] Add deserialize overloads that take a TypeRef

2 participants