Как мне разобрать универсальный параметр класса из JSON в Scala?

У меня есть общая черта добытчика

trait Getter[A] {
  def get: A
}

и я хотел бы разобрать JSON в список объектов, реализующих эту черту. Две такие реализации:

case class CoalesceGetter[A](getters: List[Getter[String]]) extends Getter[A] {
  override def get: A = getters.map(_.get).find(_ != null).orNull
}

case class AsnGetter(ipGetter: Getter[String]) extends Getter[Long] {
  override def get: Long = 99L // dummy function
}

Я хотел бы разобрать JSON в правильное Getter класс, основанный на свойстве под названием function что соответствует классу и type который соответствует универсальному типу в случае геттеров, которые нуждаются в универсальном (оба свойства являются строками в BLOB-объекте json, который я анализирую). Я смотрел на нестандартные сериализаторы для json4s, но не понимаю, как работать с дженериками. Любая помощь приветствуется!

1 ответ

Прежде всего, я не думаю, что это хорошая идея - jsonify классов с аргументом типа. Я думаю, что это лучший дизайн, чтобы определить нетипизированные (case) классы, которые являются прямым эквивалентом вашего объекта json, и использовать стандартное чтение / запись json, как предусмотрено многими библиотеками.

Но затем, чтобы ответить на ваш вопрос, я хотел бы ответить еще на один вопрос: как бы вы сделали это "вручную"? Т.е. как бы вы писали и читали разные CoalesceGetter[A] с разными A?

Вот предложение: поместите тип arg в поле json:

"ofInt":   {"type-arg":"Int", "getters":[ ... list of getters in json ...]},
"ofDouble":{"type-arg":"Double", "getters":[ ... list of getters in json ...]}

Теперь, если вы напишите читателю, как вы будете создавать экземпляры 2 ofInt и ofDouble, зная аргументы типа "Int" и "Double" (которые являются строковыми!).

Я вижу 2 решения:

1) Либо у вас есть жестко закодированная карта типа arg-type => фактический тип scala

 argType match{
   case "Int"    => new CoalesceGetter[Int](...)
   case "Double" => new CoalesceGetter[Double](...)
 }

2) Или вы сохраняете и считываете обобщенный тип как строковое значение в строке типа arg, например java Class.forName (см., Например, [ /questions/30881688/java-kak-sozdat-ekzemplyar-klassa-iz-stroki/30881701#30881701). Но это действительно очень плохая идея ИМХО.

(примечание: если вы хотите сериализовать какой-либо объект только для того, чтобы позже перезагрузить его или на другом компьютере, не используйте json, а используйте специальную сериализацию, такую ​​как Java Serialization или kryo, которую использует spark)

Другие вопросы по тегам