Skip to content

Commit

Permalink
Added maps support to encoders
Browse files Browse the repository at this point in the history
  • Loading branch information
sksamuel committed Apr 15, 2024
1 parent d28dbce commit 8ff9455
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ fun interface Encoder<T> {
BigDecimal::class -> BigDecimalStringEncoder
Set::class -> GenericArraySetEncoder(encoderFor(type.arguments.first().type!!))
List::class -> GenericArrayListEncoder(encoderFor(type.arguments.first().type!!))
Map::class -> MapEncoder(encoderFor(type.arguments[1].type!!))
is KClass<*> -> if (classifier.java.isEnum) EnumEncoder<Enum<*>>() else error("Unsupported type $type")
else -> error("Unsupported type $type")
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.sksamuel.centurion.avro.encoders

import org.apache.avro.Schema
import org.apache.avro.generic.GenericArray
import org.apache.avro.generic.GenericData

/**
Expand Down Expand Up @@ -29,9 +30,18 @@ class GenericArrayListEncoder<T>(private val encoder: Encoder<T>) : Encoder<List
* An [Encoder] for Sets of [T] that encodes into an Avro [GenericArray].
*/
class GenericArraySetEncoder<T>(private val encoder: Encoder<T>) : Encoder<Set<T>> {
override fun encode(schema: Schema, value: Set<T>): Any {
override fun encode(schema: Schema, value: Set<T>): GenericArray<Any> {
require(schema.type == Schema.Type.ARRAY)
val elements = value.map { encoder.encode(schema.elementType, it) }
return GenericData.Array<T>(elements.size, schema).also { it.addAll(elements as Collection<T>) }
val array = GenericData.get().newArray(null, elements.size, schema) as GenericArray<Any>
array.addAll(elements)
return array
}
}

class MapEncoder<T>(private val encoder: Encoder<T>) : Encoder<Map<String, T>> {
override fun encode(schema: Schema, value: Map<String, T>): Map<String, Any?> {
require(schema.type == Schema.Type.MAP)
return value.mapValues { encoder.encode(schema.valueType, it.value) }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,38 @@ class ReflectionRecordEncoderTest : FunSpec({
Foo(listOf(1, 2), listOf(1L, null, 2L), listOf(Wine.Shiraz, Wine.Malbec))
) shouldBe expected
}

test("maps") {
data class Foo(val map: Map<String, Int>)

val map = mapOf("a" to 1, "b" to 2)

val schema = SchemaBuilder.record("Foo").namespace(Foo::class.java.packageName)
.fields()
.name("map").type().map().values(SchemaBuilder.builder().intType()).noDefault()
.endRecord()

val record = GenericData.Record(schema)
record.put("map", map)

ReflectionRecordEncoder().encode(schema, Foo(map)) shouldBe record
}

test("maps of maps") {
data class Foo(val map: Map<String, Map<String, Int>>)

val maps = mapOf("a" to mapOf("a" to 1, "b" to 2), "b" to mapOf("a" to 3, "b" to 4))

val schema = SchemaBuilder.record("Foo").namespace(Foo::class.java.packageName)
.fields()
.name("map").type().map().values(SchemaBuilder.builder().map().values().intType()).noDefault()
.endRecord()

val record = GenericData.Record(schema)
record.put("map", maps)

ReflectionRecordEncoder().encode(schema, Foo(maps)) shouldBe record
}
})

enum class Wine { Shiraz, Malbec }
9 changes: 9 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
## Changelog

### 1.1.0

* Added Map encoding support

### 1.1.0

* Added Avro4s port of Encoders, Decoder, Writers and Readers

0 comments on commit 8ff9455

Please sign in to comment.