fix(kotlin-generator): add @AvroAlias on union subtype wrappers#477
fix(kotlin-generator): add @AvroAlias on union subtype wrappers#477jantoebes wants to merge 2 commits intoavro-kotlin:mainfrom
Conversation
Value-class wrappers generated inside a sealed interface for a complex
Avro union had no @AvroAlias pointing at the inner Avro full name, so
PolymorphicResolver could not map the incoming schema fullName
(e.g. "com.example.MyRecord", "int", "map") to the wrapper
SerialName ("ForMyRecord", "ForInt", "ForMap") at runtime.
This caused SerializationException: 'Serializer for subclass ... is not
found' on decode for every multi-type union.
Fix: emit @AvroAlias(subSchema.fullName) on each value-class wrapper so
AbstractPolymorphicDecoder can resolve the subtype via the existing
alias lookup in PolymorphicResolver.
|
Hello, thanks for the contribution. However, you are fixing the symptom, and not the root cause. Quickly thinking, the issue should be in the polymorphic resolver/decoder, as the string is wrapped into a value class, it is actually only using the serial name of the type, while it should instead use the produced schema name of the type. You can try to fix it! Probably create a test in the core module, testing that encoding and decoding a union with a mix of value class' primitives and named types like enums / record. I think you will hit the same error 👀 |
|
You're right, that was fixing the symptom. I've opened #479 which fixes the root cause directly in PolymorphicResolver - instead of using the serial name as the lookup key, it now resolves the actual Avro schema name the type produces in the union (unwrapping value classes down to the primitive type name). The alias workaround in the generator is no longer needed with that fix in place. |
Summary
Value-class wrappers generated inside a sealed interface for a complex Avro union had no
@AvroAliaspointing at the inner Avro full name, soPolymorphicResolvercould not map the incoming schemafullName(e.g.com.example.MyRecord,int,map) to the wrapperSerialName(ForMyRecord,ForInt,ForMap) at runtime.This caused
SerializationException: Serializer for subclass ... is not foundon decode for every multi-type union.Fix
Emit
@AvroAlias(subSchema.fullName)on each value-class wrapper soAbstractPolymorphicDecodercan resolve the subtype via the existing alias lookup inPolymorphicResolver(seecore/src/main/kotlin/com/github/avrokotlin/avro4k/internal/PolymorphicResolver.kt).Before
After
Test evidence
expected-sourcesfixtures updated automatically by the localupdateExpectedGeneratedSourcestest path.CI=true ./gradlew testpasses across all modules (core,kotlin-generator,gradle-plugin,confluent-kafka-serializer).Notes
Applies to every
fullName-bearing subschema (records, enums, fixed, and primitives/arrays/maps whosefullName == simpleName). No behavioural change for single-type or nullable-only unions (they do not hitgenerateSealedInterface).