1

avro4s用来帮助 avro 序列化和反序列化。

我有一个包含Timestamps 的案例类,需要在将记录发布到 Kafka 之前将这些Timestamps 转换为格式良好的字符串;默认编码器正在将我Timestamp的 s 转换为Longs。我读到我需要编写一个解码器和编码器(来自avro4s自述文件)。

这是我的案例类:

case class MembershipRecordEvent(id: String,
                                 userHandle: String,
                                 planId: String,
                                 teamId: Option[String] = None,
                                 note: Option[String] = None,
                                 startDate: Timestamp,
                                 endDate: Option[Timestamp] = None,
                                 eventName: Option[String] = None,
                                 eventDate: Timestamp)

我编写了以下编码器:

Test.scala

def test() = {
implicit object MembershipRecordEventEncoder extends Encoder[MembershipRecordEvent] {
  override def encode(t: MembershipRecordEvent, schema: Schema) = {
    val dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss")
    val record = new GenericData.Record(schema)
    record.put("id", t.id)
    record.put("userHandle", t.userHandle)
    record.put("teamId", t.teamId.orNull)
    record.put("note", t.note.orNull)
    record.put("startDate", dateFormat.format(t.startDate))
    record.put("endDate", if(t.endDate.isDefined) dateFormat.format(t.endDate.get) else null)
    record.put("eventName", t.eventName.orNull)
    record.put("eventDate", dateFormat.format(t.eventDate))
    record
    }
  }

val recordInAvro2 = Encoder[MembershipRecordEvent].encode(testRecord, AvroSchema[MembershipRecordEvent]).asInstanceOf[GenericRecord]
    println(recordInAvro2)
}

如果我像上面所做的那样声明 my implicit objectin line,它会创建GenericRecord我正在寻找的那个。我试图将其抽象implicit object为一个文件,包装在一个对象中,并import Implicits._使用我的自定义编码器。

Implicits.scala

object Implicits {
implicit object MembershipRecordEventEncoder extends Encoder[MembershipRecordEvent] {
  override def encode(t: MembershipRecordEvent, schema: Schema) = {
    val dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss")
    val record = new GenericData.Record(schema)
    record.put("id", t.id)
    record.put("userHandle", t.userHandle)
    record.put("teamId", t.teamId.orNull)
    record.put("note", t.note.orNull)
    record.put("startDate", dateFormat.format(t.startDate))
    record.put("endDate", if(t.endDate.isDefined) dateFormat.format(t.endDate.get) else null)
    record.put("eventName", t.eventName.orNull)
    record.put("eventDate", dateFormat.format(t.eventDate))
    record
    }
  }
}

Test.scala

import Implicits._
val recordInAvro2 = Encoder[MembershipRecordEvent].encode(testRecord, AvroSchema[MembershipRecordEvent]).asInstanceOf[GenericRecord]
    println(recordInAvro2)

它无法使用我的编码器(没有达到我的断点)。我已经尝试了无数的方法来尝试看看为什么它没有成功。

如何正确导入隐式对象?

有没有更简单的解决方案来将我case class的 s编码TimestampStrings 而无需为整个 s 编写编码器case class

4

1 回答 1

1

TL;博士

正如上述评论之一所建议的,您可以将其放在伴随对象中。

更长的版本:

可能您有另一个编码器,用于代替您在Implicits.

我将引用SCALA 在哪里寻找暗示?

当需要某个名称的值时,会在词法范围内搜索具有该名称的值。类似地,当需要某种类型的隐式值时,会在词法范围内搜索具有该类型的值。

任何可以用其“简单”名称引用的值,而不使用点分语法从另一个值中选择,都是合格的隐式值。可能有不止一个这样的值,因为它们有不同的名称。

在这种情况下,重载决议用于选择其中之一。当作用域中的多个术语具有该名称时,重载解决算法与为给定名称选择引用的算法相同。例如,println 被重载,并且每个重载都采用不同的参数类型。调用 println 需要选择正确的重载方法。

在隐式搜索中,重载决策会在多个具有相同所需类型的值中选择一个值。通常这需要选择相对于其他符合条件的值在子类中定义的更窄的类型或值。

必须使用其简单名称访问值的规则意味着应用名称绑定的常规规则。

总之,x 的定义遮蔽了封闭范围内的定义。但是 x 的绑定也可以通过本地导入引入。导入的符号不能覆盖封闭范围内同名的定义。同样,通配符导入不能覆盖特定名称的导入,并且从其他源文件可见的当前包中的名称不能覆盖导入或本地定义。

这些是确定 x 在给定上下文中的含义的常规规则,并且还确定哪个值 x 可以通过其简单名称访问并符合隐含条件。

这意味着可以通过使用同名术语隐藏范围来禁用隐式范围。

现在我将说明伴随对象的逻辑:

隐式语法可以通过利用“隐式范围”来避免进口税,这当然是一种“罪恶税”,这取决于隐式的类型而不是词汇范围内的进口。

当需要类型 T 的隐式时,隐式范围包括伴随对象 T:当需要 F[T] 时,隐式范围包括 F 的伴随对象和类型参数的伴随对象,例如,对象 C 代表 F[C ]。

此外,隐式作用域包括 F 和 C 的基类的同伴,包括包对象,例如 p 代表 pF

于 2020-08-06T19:54:09.080 回答