Avro 生成的 json 转换类问题 [kotlin]

Jee*_*eef 2 java jackson avro kotlin

我在编组/解组avro生成的类时遇到了一个奇怪的问题。我得到的错误是抛出一个不是枚举错误 - 除了我的类中没有任何枚举。

错误具体是这样的:

com.fasterxml.jackson.databind.JsonMappingException:不是枚举:{"type":"record","name":"TimeUpdateTopic","namespace":"org.company.mmd.time","fields":[ {"name":"time","type":"double"}]}(通过参考链:org.company.mmd.time.TimeUpdateTopic["schema"]->org.apache.avro.Schema$RecordSchema[ "enumDefault"])

测试用例

import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule
import org.junit.Test

class TimeUpdateTopicTest {
    val objectMapper = ObjectMapper().registerModule(JavaTimeModule())

    @Test
    fun decode() {
        val t = TimeUpdateTopic(1.0)
        objectMapper.writeValueAsString(t)
    }
}
Run Code Online (Sandbox Code Playgroud)

AVDL

@namespace("org.company.mmd.time")
protocol TimeMonitor {

  record TimeUpdateTopic {
    double time;
  }
}
Run Code Online (Sandbox Code Playgroud)

avro 任务生成的 Java 类

import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule
import org.junit.Test

class TimeUpdateTopicTest {
    val objectMapper = ObjectMapper().registerModule(JavaTimeModule())

    @Test
    fun decode() {
        val t = TimeUpdateTopic(1.0)
        objectMapper.writeValueAsString(t)
    }
}
Run Code Online (Sandbox Code Playgroud)

我在这里做一些愚蠢和/或错误的事情吗?或者这是一个实际的错误

更新

我可以使用此函数获取 JSON:

  inline fun <reified T: SpecificRecordBase> StringFromAvroGenerated(obj: T) : String {
        val schema = obj.schema
        val writer = SpecificDatumWriter(T::class.java)
        val stream = ByteArrayOutputStream()
        var jsonEncoder = EncoderFactory.get().jsonEncoder(schema, stream)
        writer.write(obj, jsonEncoder)
        jsonEncoder.flush()
        return stream.toString("UTF-8")
    }
Run Code Online (Sandbox Code Playgroud)

但我假设这应该是杰克逊自动的

Jee*_*eef 6

所以看起来有两种方法可以解决我的问题(感谢JsonMappingException 在将 avro 生成的对象序列化为 json 时

编写 Jackson MixIn 来处理getSchema调用

所以第一个选项要求我创建一个像这样的 Mixin:

abstract class AvroMixIn {
    @JsonIgnore
    abstract fun getSchema(): org.apache.avro.Schema
    @JsonIgnore
    abstract fun getSpecificData() : org.apache.avro.specific.SpecificData
}
Run Code Online (Sandbox Code Playgroud)

然后当我制作对象映射器时:

val objectMapper = ObjectMapper()
     .registerModule(JavaTimeModule())
     .addMixIn(Object::class.java, AvroMixIn::class.java)
Run Code Online (Sandbox Code Playgroud)

我选择Object::class.java而不是实际的类,因为它应该适用于所有类。可能更好的解决方案是将其应用于所有 AvroGenerated 的共享基类。

重写 Avro Velocity Templates 以自动添加这个

这实际上是我采取的第一种方法,因为它看起来更“无情”。

1) 检查 avro 项目 2) 将enum.vm, fixed.vm, protocol.vm,复制record.vm/avro_templates我的项目主根目录之外的目录中 3) 将@com.fasterxml.jackson.annotation.JsonIgnore属性添加到模板中:

#end
  @com.fasterxml.jackson.annotation.JsonIgnore
  public org.apache.avro.specific.SpecificData getSpecificData() { return MODEL$; }
  @com.fasterxml.jackson.annotation.JsonIgnore
  public org.apache.avro.Schema getSchema() { return SCHEMA$; }
  // Used by DatumWriter.  Applications should not call.
Run Code Online (Sandbox Code Playgroud)

4)更新gradle任务:

avro {
    dateTimeLogicalType="JSR310"
    templateDirectory = "avro_templates/"
}
Run Code Online (Sandbox Code Playgroud)

5)重新构建avro类

(现在一切正常)