Неявный объект работает встроенно, но не при импорте - PullRequest
1 голос
/ 06 августа 2020

Я использую avro4s, чтобы помочь с сериализацией и десериализацией avro.

У меня есть класс case, который включает Timestamp s, и мне нужно, чтобы эти Timestamp s были преобразованы в красиво отформатированные строки, прежде чем я publi sh записи в Кафку; кодировщик по умолчанию преобразует мои Timestamp s в Long s. Я прочитал, что мне нужно написать декодер и кодировщик (из avro4s readme).

Вот мой класс case:

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)
}

Если я объявлю свой implicit object в строке, как я сделал выше, он создаст 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 от Timestamp s до String s без записи кодировщика для всего case class?

1 Ответ

1 голос
/ 06 августа 2020

TL; DR

Как предлагается в одном из комментариев выше, вы можете поместить его в сопутствующий объект.

Более длинная версия:

Возможно, у вас есть другой кодировщик, который используется вместо кодировщика, определенного в Implicits.

Я процитирую некоторые фразы из ГДЕ SCALA ИЩИТЕ ПОСЛЕДСТВИЯ?

Когда требуется значение с определенным именем, в лексической области ищется значение с таким именем. Точно так же, когда требуется неявное значение определенного типа, в лексической области ищется значение с этим типом.

Любое такое значение, на которое можно ссылаться с его «простым» именем, без выбора другого значения с помощью пунктирный синтаксис - допустимое неявное значение. Таких значений может быть несколько, потому что они имеют разные имена.

В этом случае разрешение перегрузки используется для выбора одного из них. Алгоритм разрешения перегрузки тот же, что и для выбора ссылки для данного имени, когда это имя есть более чем у одного термина в области видимости. Например, println перегружен, и каждая перегрузка принимает другой тип параметра. Вызов println требует выбора правильного перегруженного метода.

При неявном поиске разрешение перегрузки выбирает значение из нескольких, имеющих один и тот же требуемый тип. Обычно это влечет за собой выбор более узкого типа или значения, определенного в подклассе, относительно других допустимых значений.

Правило, согласно которому значение должно быть доступно с использованием его простого имени, означает, что применяются обычные правила привязки имени.

Таким образом, определение x затеняет определение во внешней области видимости. Но привязка для x также может быть введена посредством локального импорта. Импортированные символы не могут заменять одноименные определения во включающей области. Точно так же импорт с подстановочными знаками не может переопределить импорт указанного c имени, а имена в текущем пакете, которые видны из других исходных файлов, не могут переопределить импорт или локальные определения.

Это обычные правила для определения того, что x означает в данном контексте, а также для определения того, какое значение x доступно по его простому имени и имеет право как неявное.

Это означает, что неявный в области видимости можно отключить, затеняя его с помощью термин с тем же именем.

Теперь я укажу сопутствующий объект logi c:

Неявный синтаксис позволяет избежать налога на импорт, который, конечно, «налог на грех» за счет использования «неявной области видимости», которая зависит от типа неявной области вместо импорта в лексической области.

Когда требуется неявный тип T, неявная область включает сопутствующий объект T : Когда требуется F [T], неявная область включает в себя как сопутствующий элемент F, так и сопутствующий элемент аргумента типа, например, объект C для F [ C].

Кроме того, неявная область видимости включает сопутствующие элементы базовых классов F и C, включая объекты пакета, такие как p для pF

...