Skip to content

Conversation

@MintsInc
Copy link
Member

@MintsInc MintsInc commented Oct 17, 2025

Context

PRs #3177 and #3180 fixed oneOf types with type erasure collisions (e.g., List<String> and List<Double>) by:

However, the deserialization side was not fixed, causing test failures in PR #3057.

Issue

When deserializing JSON for oneOf types with parameterized types that have the same erasure, the deserializer uses .class which loses generic type information:

// Both attempts match because List<String> and List<Double> both erase to List.class
tmp = tree.traverse(jp.getCodec()).readValueAs(List.class);  // matches List<String>
...
tmp = tree.traverse(jp.getCodec()).readValueAs(List.class);  // also matches List<Double>!

This causes match = 2, leading to a fallback that tries to deserialize the array as a Map<String, Object>, resulting in:

Cannot deserialize value of type `java.util.LinkedHashMap<java.lang.String,java.lang.Object>`
from Array value (token `JsonToken.START_ARRAY`)

This failure occurred in PR #3057 when testing CustomAttributeValuesUnion with oneOf: String, List<String>, Double, List<Double>.

Changes

Updated .generator/src/generator/templates/modelOneOf.j2 to use TypeReference<T> for parameterized types instead of .class:

  1. Added is_parameterized_type() helper in formatter.py to detect generic types
  2. Registered the filter in cli.py
  3. Updated template to conditionally use:
    • TypeReference<List<String>> for parameterized types (preserves generic info)
    • .class for simple types (no change to existing behavior)

Before:

tmp = tree.traverse(jp.getCodec()).readValueAs(List.class);

After:

tmp = tree.traverse(jp.getCodec()).readValueAs(new TypeReference<List<String>>() {});

This ensures Jackson can distinguish between List<String> and List<Double> during deserialization, preventing multiple matches.

Changes to already existing codebase

  • 3 pre-existing oneOf types with parameterized types exist in the codebase, this is not breaking
  • All existing tests pass (CI green), confirming backward compatibility
  • More correct behavior: Uses full generic type information for deserialization
  • No change for non-parameterized types (String, Integer, etc.)

Test

The fix resolves the compilation failure in PR #3057's test: the ci run after having the current commit on top of the problematic branch is green

Copy link
Member Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

@MintsInc MintsInc marked this pull request as ready for review October 17, 2025 08:38
@MintsInc MintsInc requested review from a team as code owners October 17, 2025 08:38
@MintsInc MintsInc added the changelog/no-changelog Changes don't appear in changelog label Oct 17, 2025
@MintsInc MintsInc merged commit 2a85824 into master Oct 17, 2025
17 of 18 checks passed
@MintsInc MintsInc deleted the ulysse.mavrocordatos/fix-oneof-deserialization branch October 17, 2025 09:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

changelog/no-changelog Changes don't appear in changelog

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants