avro-kotlin / avro4k

Avro format support for Kotlin
Apache License 2.0
194 stars 37 forks source link

Encode/decode to/from a stream seems to be broken? #87

Closed rocketraman closed 3 years ago

rocketraman commented 3 years ago

I tried to use this code to encode to a stream:

val serializer = Foo.serializer()
Avro.default.openOutputStream(serializer) {
    encodeFormat = AvroEncodeFormat.Binary
}.to(outStream).write(value).flush()

and this code to decode:

val serializer = Foo.serializer()
Avro.default.openInputStream(serializer) {
    decodeFormat = AvroDecodeFormat.Binary(Avro.default.schema(serializer))
}.from(inStream).next()

The underlying class that is being encoded is:

@Serializable
data class Foo(
  @Serializable(with = LocalDateSerializer::class)
  val d: LocalDate,
  val f: Float,
  val s: String
)

However, this appears to read more bytes than it writes or something, because the underlying system in which I'm using these classes throws an EOFException.

If I use the kotlinx-serialization default Json encoder and my own DataOutputStream and DataInputStream wrappers to writeUTF and readUTF (and a custom implementation of LocalDateSerializer), everything works fine.

I admit I haven't done a lot more investigation into what I could potentially be doing wrong, because honestly I don't have time to do it, but thought I would throw this out there. Any ideas?

thake commented 3 years ago

@rocketraman I tried to reproduce the issue but was not successful in doing so.

My code looks like this:

@Serializable
data class BugFoo(
    @Serializable(with = LocalDateSerializer::class)
    val d: LocalDate,
    val f: Float,
    val s: String
)

fun main() {
    val byteArrayOutputStream = ByteArrayOutputStream()
    val value = BugFoo(LocalDate.of(2002,1,1),2.3f,"34")
    val serializer = BugFoo.serializer()
    Avro.default.openOutputStream(serializer) {
        encodeFormat = AvroEncodeFormat.Binary
    }.to(byteArrayOutputStream).write(value).flush()

    val byteArrayInputStream = ByteArrayInputStream(byteArrayOutputStream.toByteArray())
    val result = Avro.default.openInputStream(serializer) {
        decodeFormat = AvroDecodeFormat.Binary(Avro.default.schema(serializer))
    }.from(byteArrayInputStream).next()

    println("Decoded from array stream: $result")
}

Output:

Decoded from array stream: BugFoo(d=2002-01-01, f=2.3, s=34)
rocketraman commented 3 years ago

I can't repro either, so closing.