Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: No more reflection and customizable logical types #175

Merged
merged 1 commit into from
Jan 27, 2024
Merged
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
5 changes: 2 additions & 3 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ dependencies {
api(libs.apache.avro)
api(libs.kotlinx.serialization.core)
implementation(libs.kotlinx.serialization.json)
implementation(kotlin("reflect"))
implementation(libs.xerial.snappy)
testImplementation(libs.kotest.junit5)
testImplementation(libs.kotest.core)
Expand All @@ -49,8 +48,8 @@ dependencies {

tasks.withType<KotlinCompile>().configureEach {
kotlinOptions.jvmTarget = "1.8"
kotlinOptions.apiVersion = "1.5"
kotlinOptions.languageVersion = "1.5"
kotlinOptions.apiVersion = "1.6"
kotlinOptions.languageVersion = "1.6"
kotlinOptions.freeCompilerArgs += "-opt-in=kotlin.RequiresOptIn"
}
java {
Expand Down
6 changes: 5 additions & 1 deletion src/main/kotlin/com/github/avrokotlin/avro4k/Avro.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,11 @@ import kotlinx.serialization.modules.contextual
import org.apache.avro.Schema
import org.apache.avro.file.CodecFactory
import org.apache.avro.generic.GenericRecord
import java.io.*
import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.InputStream
import java.io.OutputStream
import java.nio.ByteBuffer
import java.nio.file.Files
import java.nio.file.Path
Expand Down
62 changes: 60 additions & 2 deletions src/main/kotlin/com/github/avrokotlin/avro4k/annotations.kt
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
@file:OptIn(ExperimentalSerializationApi::class)

package com.github.avrokotlin.avro4k

import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.SerialInfo
import kotlinx.serialization.descriptors.PrimitiveKind
import org.apache.avro.LogicalTypes
import org.apache.avro.Schema
import org.apache.avro.SchemaBuilder
import org.intellij.lang.annotations.Language

@SerialInfo
Expand All @@ -23,7 +28,57 @@ annotation class AvroName(val value: String)

@SerialInfo
@Target(AnnotationTarget.PROPERTY, AnnotationTarget.CLASS)
annotation class ScalePrecision(val scale: Int, val precision: Int)
annotation class ScalePrecision(val scale: Int = 2, val precision: Int = 8)

@SerialInfo
@Target(AnnotationTarget.PROPERTY)
annotation class AvroDecimalLogicalType(val schema: LogicalDecimalTypeEnum = LogicalDecimalTypeEnum.BYTES)

enum class LogicalDecimalTypeEnum {
BYTES,
STRING,

/**
* Fixed must be accompanied with [AvroFixed]
*/
FIXED,
}

@SerialInfo
@Target(AnnotationTarget.PROPERTY)
annotation class AvroUuidLogicalType

@SerialInfo
@Target(AnnotationTarget.PROPERTY)
annotation class AvroTimeLogicalType(val type: LogicalTimeTypeEnum)

enum class LogicalTimeTypeEnum(val logicalTypeName: String, val kind: PrimitiveKind, val schemaFor: () -> Schema) {
DATE("date", PrimitiveKind.INT, { LogicalTypes.date().addToSchema(SchemaBuilder.builder().intType()) }),
TIME_MILLIS(
"time-millis",
PrimitiveKind.INT,
{ LogicalTypes.timeMillis().addToSchema(SchemaBuilder.builder().intType()) }),
TIME_MICROS(
"time-micros",
PrimitiveKind.LONG,
{ LogicalTypes.timeMicros().addToSchema(SchemaBuilder.builder().longType()) }),
TIMESTAMP_MILLIS(
"timestamp-millis",
PrimitiveKind.LONG,
{ LogicalTypes.timestampMillis().addToSchema(SchemaBuilder.builder().longType()) }),
TIMESTAMP_MICROS(
"timestamp-micros",
PrimitiveKind.LONG,
{ LogicalTypes.timestampMicros().addToSchema(SchemaBuilder.builder().longType()) }),
LOCAL_TIMESTAMP_MILLIS(
"local-timestamp-millis",
PrimitiveKind.LONG,
{ LogicalTypes.localTimestampMillis().addToSchema(SchemaBuilder.builder().longType()) }),
LOCAL_TIMESTAMP_MICROS(
"local-timestamp-micros",
PrimitiveKind.LONG,
{ LogicalTypes.localTimestampMicros().addToSchema(SchemaBuilder.builder().longType()) }),
}

@SerialInfo
@Target(AnnotationTarget.CLASS)
Expand All @@ -38,7 +93,10 @@ annotation class AvroDoc(val value: String)
annotation class AvroAlias(vararg val value: String)

@SerialInfo
@Deprecated(message = "Will be removed in the next major release", replaceWith = ReplaceWith("@AvroAlias(alias1, alias2)"))
@Deprecated(
message = "Will be removed in the next major release",
replaceWith = ReplaceWith("@AvroAlias(alias1, alias2)")
)
@Target(AnnotationTarget.PROPERTY, AnnotationTarget.CLASS)
annotation class AvroAliases(val value: Array<String>)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ object StringFromAvroValue : FromAvroValue<Any?, String> {
is CharSequence -> value.toString()
is ByteBuffer -> String(value.array())
null -> throw SerializationException("Cannot decode <null> as a string")
else -> throw SerializationException("Unsupported type for String [is ${value.javaClass}]")
else -> throw SerializationException("Unsupported type for String [is ${value::class.qualifiedName}]")
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,15 @@ class MapDecoder(
return when (val v = value()) {
is Float -> v
null -> throw SerializationException("Cannot decode <null> as a Float")
else -> throw SerializationException("Unsupported type for Float ${v.javaClass}")
else -> throw SerializationException("Unsupported type for Float ${v::class.qualifiedName}")
}
}

override fun decodeInt(): Int {
return when (val v = value()) {
is Int -> v
null -> throw SerializationException("Cannot decode <null> as a Int")
else -> throw SerializationException("Unsupported type for Int ${v.javaClass}")
else -> throw SerializationException("Unsupported type for Int ${v::class.qualifiedName}")
}
}

Expand All @@ -63,7 +63,7 @@ class MapDecoder(
is Long -> v
is Int -> v.toLong()
null -> throw SerializationException("Cannot decode <null> as a Long")
else -> throw SerializationException("Unsupported type for Long ${v.javaClass}")
else -> throw SerializationException("Unsupported type for Long ${v::class.qualifiedName}")
}
}

Expand All @@ -72,7 +72,7 @@ class MapDecoder(
is Double -> v
is Float -> v.toDouble()
null -> throw SerializationException("Cannot decode <null> as a Double")
else -> throw SerializationException("Unsupported type for Double ${v.javaClass}")
else -> throw SerializationException("Unsupported type for Double ${v::class.qualifiedName}")
}
}

Expand All @@ -81,15 +81,15 @@ class MapDecoder(
is Byte -> v
is Int -> v.toByte()
null -> throw SerializationException("Cannot decode <null> as a Byte")
else -> throw SerializationException("Unsupported type for Byte ${v.javaClass}")
else -> throw SerializationException("Unsupported type for Byte ${v::class.qualifiedName}")
}
}

override fun decodeBoolean(): Boolean {
return when (val v = value()) {
is Boolean -> v
null -> throw SerializationException("Cannot decode <null> as a Boolean")
else -> throw SerializationException("Unsupported type for Boolean ${v.javaClass}")
else -> throw SerializationException("Unsupported type for Boolean. Actual: ${v::class.qualifiedName}")
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ class RecordDecoder(
return when (val v = fieldValue()) {
is Boolean -> v
null -> throw SerializationException("Cannot decode <null> as a Boolean")
else -> throw SerializationException("Unsupported type for Boolean ${v.javaClass}")
else -> throw SerializationException("Unsupported type for Boolean ${v::class.qualifiedName}")
}
}

Expand All @@ -119,7 +119,7 @@ class RecordDecoder(
is Byte -> v
is Int -> if (v < 255) v.toByte() else throw SerializationException("Out of bound integer cannot be converted to byte [$v]")
null -> throw SerializationException("Cannot decode <null> as a Byte")
else -> throw SerializationException("Unsupported type for Byte ${v.javaClass}")
else -> throw SerializationException("Unsupported type for Byte ${v::class.qualifiedName}")
}
}

Expand All @@ -141,15 +141,15 @@ class RecordDecoder(
return when (val v = fieldValue()) {
is Float -> v
null -> throw SerializationException("Cannot decode <null> as a Float")
else -> throw SerializationException("Unsupported type for Float ${v.javaClass}")
else -> throw SerializationException("Unsupported type for Float ${v::class.qualifiedName}")
}
}

override fun decodeInt(): Int {
return when (val v = fieldValue()) {
is Int -> v
null -> throw SerializationException("Cannot decode <null> as a Int")
else -> throw SerializationException("Unsupported type for Int ${v.javaClass}")
else -> throw SerializationException("Unsupported type for Int ${v::class.qualifiedName}")
}
}

Expand All @@ -158,7 +158,7 @@ class RecordDecoder(
is Long -> v
is Int -> v.toLong()
null -> throw SerializationException("Cannot decode <null> as a Long")
else -> throw SerializationException("Unsupported type for Long [is ${v.javaClass}]")
else -> throw SerializationException("Unsupported type for Long [is ${v::class.qualifiedName}]")
}
}

Expand All @@ -167,7 +167,7 @@ class RecordDecoder(
is Double -> v
is Float -> v.toDouble()
null -> throw SerializationException("Cannot decode <null> as a Double")
else -> throw SerializationException("Unsupported type for Double ${v.javaClass}")
else -> throw SerializationException("Unsupported type for Double ${v::class.qualifiedName}")
}
}

Expand Down

This file was deleted.

Loading
Loading