Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion core/src/main/kotlin/com/github/avrokotlin/avro4k/Avro.kt
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public sealed class Avro(
private val schemaCache: Cache<SerialDescriptor, Schema> = WeakKeyCache()

internal val recordResolver = RecordResolver(this)
internal val polymorphicResolver = PolymorphicResolver(serializersModule)
internal val polymorphicResolver = PolymorphicResolver(serializersModule) { schema(it).fullName }
internal val enumResolver = EnumResolver()

public companion object Default : Avro(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,18 @@ import com.github.avrokotlin.avro4k.AvroAlias
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.modules.SerializersModule

internal class PolymorphicResolver(private val serializersModule: SerializersModule) {
internal class PolymorphicResolver(
private val serializersModule: SerializersModule,
private val schemaNameResolver: (SerialDescriptor) -> String,
) {
private val cache = WeakKeyCache<SerialDescriptor, Map<String, String>>()

fun getFullNamesAndAliasesToSerialName(descriptor: SerialDescriptor): Map<String, String> {
return cache.getOrPut(descriptor) {
descriptor.possibleSerializationSubclasses(serializersModule)
.flatMap {
sequence {
yield(it.nonNullSerialName to it.nonNullSerialName)
yield(schemaNameResolver(it) to it.nonNullSerialName)
it.findAnnotation<AvroAlias>()?.value?.forEach { alias ->
yield(alias to it.nonNullSerialName)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import com.github.avrokotlin.avro4k.recordWithSchema
import com.github.avrokotlin.avro4k.schema
import io.kotest.core.spec.style.StringSpec
import kotlinx.serialization.Serializable
import org.apache.avro.generic.GenericData

internal class SealedClassEncodingTest : StringSpec({
"encode/decode sealed classes" {
Expand All @@ -15,6 +16,13 @@ internal class SealedClassEncodingTest : StringSpec({
AvroAssertions.assertThat<Operation>(Operation.Binary.Add(1, 2))
.isEncodedAs(recordWithSchema(Avro.schema<Operation.Binary.Add>(), 1, 2))
}
"encode/decode sealed class union with value class primitive, enum and record subtypes" {
val shapeSchema = Avro.schema<Shape>()
val colorSchema = shapeSchema.types.first { it.name == "Color" }
AvroAssertions.assertThat<Shape>(Shape.Label("hello")).isEncodedAs("hello")
AvroAssertions.assertThat<Shape>(Shape.Color.RED).isEncodedAs(GenericData.get().createEnum("RED", colorSchema))
AvroAssertions.assertThat<Shape>(Shape.Circle(5)).isEncodedAs(recordWithSchema(Avro.schema<Shape.Circle>(), 5))
}
"encode/decode nullable sealed classes" {
AvroAssertions.assertThat(ReferencingNullableSealedClass(Operation.Binary.Add(1, 2)))
.isEncodedAs(record(recordWithSchema(Avro.schema<Operation.Binary.Add>(), 1, 2)))
Expand All @@ -27,6 +35,19 @@ internal class SealedClassEncodingTest : StringSpec({
.isEncodedAs(null)
}
}) {
@Serializable
private sealed interface Shape {
@JvmInline
@Serializable
value class Label(val value: String) : Shape

@Serializable
enum class Color : Shape { RED, BLUE }

@Serializable
data class Circle(val radius: Int) : Shape
}

@Serializable
private data class ReferencingSealedClass(
val notNullable: Operation,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,7 @@ public class KotlinGenerator(
* ```kotlin
* @Serializable
* sealed interface <potentialAnonymousBaseName>Union {
* @AvroAlias("<Type full name>")
* @JvmInline
* @Serializable
* value class For<Type name>(val value: <Type full name>) : <potentialAnonymousBaseName>Union
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
ExperimentalAvro4kApi::class,
)

import com.github.avrokotlin.avro4k.AvroAlias
import com.github.avrokotlin.avro4k.AvroDefault
import com.github.avrokotlin.avro4k.ExperimentalAvro4kApi
import com.github.avrokotlin.avro4k.InternalAvro4kApi
Expand All @@ -25,18 +26,21 @@ public data class ComplexUnionInRecord(
@Serializable
@AvroGenerated("""["null",{"type":"record","name":"NestedRecord","fields":[{"name":"id","type":"string"},{"name":"value","type":"int"}]},{"type":"enum","name":"Status","symbols":["ACTIVE","INACTIVE","PENDING"]},{"type":"array","items":"string"}]""")
public sealed interface TheFieldUnion {
@AvroAlias("NestedRecord")
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Don't forget to re-run actionsBeforeCommit

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

ok done! thx for the review :-D

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

But why the avro alias annotation is still present?

@JvmInline
@Serializable
public value class ForNestedRecord(
public val `value`: NestedRecord,
) : TheFieldUnion

@AvroAlias("Status")
@JvmInline
@Serializable
public value class ForStatus(
public val `value`: Status,
) : TheFieldUnion

@AvroAlias("array")
@JvmInline
@Serializable
public value class ForArray(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,14 @@ public data class CamelCaseRecord(
@Serializable
@AvroGenerated("""["string",{"type":"enum","name":"StatusFlag","namespace":"ns","symbols":["ACTIVE","INACTIVE"]},"null"]""")
public sealed interface AccountStatusUnion {
@AvroAlias("string")
@JvmInline
@Serializable
public value class ForString(
public val `value`: String,
) : AccountStatusUnion

@AvroAlias("ns.StatusFlag")
@JvmInline
@Serializable
public value class ForStatusFlag(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
ExperimentalAvro4kApi::class,
)

import com.github.avrokotlin.avro4k.AvroAlias
import com.github.avrokotlin.avro4k.AvroFixed
import com.github.avrokotlin.avro4k.ExperimentalAvro4kApi
import com.github.avrokotlin.avro4k.InternalAvro4kApi
Expand All @@ -20,43 +21,50 @@ import kotlinx.serialization.Serializable
@Serializable
@AvroGenerated("""["null","string","int",{"type":"record","name":"NestedRecord","fields":[{"name":"field","type":"string","doc":"field doc"}]},{"type":"enum","name":"AnEnum","symbols":["A","B","C"]},{"type":"fixed","name":"AFixed","size":5},{"type":"array","items":"int"},{"type":"map","values":["null","double"]}]""")
public sealed interface TestSchema {
@AvroAlias("string")
@JvmInline
@Serializable
public value class ForString(
public val `value`: String,
) : TestSchema

@AvroAlias("int")
@JvmInline
@Serializable
public value class ForInt(
public val `value`: Int,
) : TestSchema

@AvroAlias("NestedRecord")
@JvmInline
@Serializable
public value class ForNestedRecord(
public val `value`: NestedRecord,
) : TestSchema

@AvroAlias("AnEnum")
@JvmInline
@Serializable
public value class ForAnEnum(
public val `value`: AnEnum,
) : TestSchema

@AvroAlias("AFixed")
@JvmInline
@Serializable
public value class ForAFixed(
@AvroFixed(size = 5)
public val `value`: ByteArray,
) : TestSchema

@AvroAlias("array")
@JvmInline
@Serializable
public value class ForArray(
public val `value`: List<Int>,
) : TestSchema

@AvroAlias("map")
@JvmInline
@Serializable
public value class ForMap(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
ExperimentalAvro4kApi::class,
)

import com.github.avrokotlin.avro4k.AvroAlias
import com.github.avrokotlin.avro4k.ExperimentalAvro4kApi
import com.github.avrokotlin.avro4k.InternalAvro4kApi
import com.github.avrokotlin.avro4k.`internal`.AvroGenerated
Expand All @@ -15,12 +16,14 @@ import kotlinx.serialization.Serializable
@Serializable
@AvroGenerated("""["double","null","int"]""")
public sealed interface TestSchemaMapUnion {
@AvroAlias("double")
@JvmInline
@Serializable
public value class ForDouble(
public val `value`: Double,
) : TestSchemaMapUnion

@AvroAlias("int")
@JvmInline
@Serializable
public value class ForInt(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
ExperimentalAvro4kApi::class,
)

import com.github.avrokotlin.avro4k.AvroAlias
import com.github.avrokotlin.avro4k.ExperimentalAvro4kApi
import com.github.avrokotlin.avro4k.InternalAvro4kApi
import com.github.avrokotlin.avro4k.`internal`.AvroGenerated
Expand All @@ -17,18 +18,21 @@ import kotlinx.serialization.Serializable
@Serializable
@AvroGenerated("""["int","null",{"type":"map","values":["string","null",{"type":"array","items":["long","null",{"type":"map","values":["boolean","null"]}]}]},{"type":"array","items":["long","null","double"]}]""")
public sealed interface TestSchema {
@AvroAlias("int")
@JvmInline
@Serializable
public value class ForInt(
public val `value`: Int,
) : TestSchema

@AvroAlias("map")
@JvmInline
@Serializable
public value class ForMap(
public val `value`: Map<String, TestSchemaMapUnion?>,
) : TestSchema

@AvroAlias("array")
@JvmInline
@Serializable
public value class ForArray(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
ExperimentalAvro4kApi::class,
)

import com.github.avrokotlin.avro4k.AvroAlias
import com.github.avrokotlin.avro4k.ExperimentalAvro4kApi
import com.github.avrokotlin.avro4k.InternalAvro4kApi
import com.github.avrokotlin.avro4k.`internal`.AvroGenerated
Expand All @@ -15,12 +16,14 @@ import kotlinx.serialization.Serializable
@Serializable
@AvroGenerated("""["long","null","double"]""")
public sealed interface TestSchemaArrayUnion {
@AvroAlias("long")
@JvmInline
@Serializable
public value class ForLong(
public val `value`: Long,
) : TestSchemaArrayUnion

@AvroAlias("double")
@JvmInline
@Serializable
public value class ForDouble(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
ExperimentalAvro4kApi::class,
)

import com.github.avrokotlin.avro4k.AvroAlias
import com.github.avrokotlin.avro4k.ExperimentalAvro4kApi
import com.github.avrokotlin.avro4k.InternalAvro4kApi
import com.github.avrokotlin.avro4k.`internal`.AvroGenerated
Expand All @@ -17,12 +18,14 @@ import kotlinx.serialization.Serializable
@Serializable
@AvroGenerated("""["long","null",{"type":"map","values":["boolean","null"]}]""")
public sealed interface TestSchemaMapArrayUnion {
@AvroAlias("long")
@JvmInline
@Serializable
public value class ForLong(
public val `value`: Long,
) : TestSchemaMapArrayUnion

@AvroAlias("map")
@JvmInline
@Serializable
public value class ForMap(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
ExperimentalAvro4kApi::class,
)

import com.github.avrokotlin.avro4k.AvroAlias
import com.github.avrokotlin.avro4k.ExperimentalAvro4kApi
import com.github.avrokotlin.avro4k.InternalAvro4kApi
import com.github.avrokotlin.avro4k.`internal`.AvroGenerated
Expand All @@ -15,12 +16,14 @@ import kotlinx.serialization.Serializable
@Serializable
@AvroGenerated("""["string","null",{"type":"array","items":["long","null",{"type":"map","values":["boolean","null"]}]}]""")
public sealed interface TestSchemaMapUnion {
@AvroAlias("string")
@JvmInline
@Serializable
public value class ForString(
public val `value`: String,
) : TestSchemaMapUnion

@AvroAlias("array")
@JvmInline
@Serializable
public value class ForArray(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
ExperimentalAvro4kApi::class,
)

import com.github.avrokotlin.avro4k.AvroAlias
import com.github.avrokotlin.avro4k.AvroFixed
import com.github.avrokotlin.avro4k.ExperimentalAvro4kApi
import com.github.avrokotlin.avro4k.InternalAvro4kApi
Expand All @@ -18,37 +19,43 @@ import ns2.Enum
@Serializable
@AvroGenerated("""[{"type":"record","name":"Record","namespace":"ns","fields":[{"name":"field","type":"int"}]},{"type":"record","name":"RecordWithoutNamespace","fields":[{"name":"field","type":"int"}]},{"type":"enum","name":"Enum","namespace":"ns2","symbols":["FIRST","SECOND"]},{"type":"fixed","name":"FixedType","size":12},"string","bytes"]""")
public sealed interface Union {
@AvroAlias("ns.Record")
@JvmInline
@Serializable
public value class ForRecord(
public val `value`: Record,
) : Union

@AvroAlias("RecordWithoutNamespace")
@JvmInline
@Serializable
public value class ForRecordWithoutNamespace(
public val `value`: RecordWithoutNamespace,
) : Union

@AvroAlias("ns2.Enum")
@JvmInline
@Serializable
public value class ForEnum(
public val `value`: Enum,
) : Union

@AvroAlias("FixedType")
@JvmInline
@Serializable
public value class ForFixedType(
@AvroFixed(size = 12)
public val `value`: ByteArray,
) : Union

@AvroAlias("string")
@JvmInline
@Serializable
public value class ForString(
public val `value`: String,
) : Union

@AvroAlias("bytes")
@JvmInline
@Serializable
public value class ForBytes(
Expand Down