Назначить любой val scala pureconfig во время чтения конфигурации

Я знаю, что это идет вразрез с самой природой Scala pureconfig ... однако... Реально ли это реализовать с помощью чтения конфигурации scala pureconfig для этого класса case, чтобы вместо строго типизированного значения (как String) для конструктора Параметр "переменная" может иметь любой тип или, по крайней мере, String, Integer, Double, Array[Strings], Array[Integer], Array[Double].

  case class Filter(
  field: String,
  operator: String,
  variable: String  // should support Int , Double , List[String], List[Int]
  )

Насколько я понимаю, ни CoProductHint, ни Custom Reader не будут работать...

2 ответа

Решение

По умолчанию pureconfig не предоставляет способ чтения Any, Если для конкретного класса вы хотели бы прочитать Any тогда вы можете определить кодек для Any в контексте этого класса:

case class Filter(field: String, operator: String, variable: Any)

implicit val readFilter = {
  implicit val readAny = new ConfigReader[Any] {
    def from(config: ConfigValue): Either[ConfigReaderFailures, Any] = {
      Right(config.unwrapped())
    }
  }
  ConfigReader[Filter]
}

и тогда вы можете прочитать Filter

val config = ConfigFactory.parseString(
    """
    {
      field: "foo"
      operator: "bar"
      variable: []
    }
    """)
println(pureconfig.loadConfig[Filter](config))
// will print Right(Filter(foo,bar,[]))

unwrapped преобразует ConfigValue в Any рекурсивно.

Так что ответ - да, если возможно, расскажите pureconfig, как читать Any,

Причина, по которой pureconfig не предоставляет кодек для Any по умолчанию это потому что Any является предком всех классов в Scala, и невозможно создать кодек для чего-либо (например, для подключения к базе данных). Когда вы знаете, что ожидаете ограниченный набор типов, таких как перечисленные вами, вы можете обернуть все в копродукт:

sealed abstract class MySupportedType
final case class MyInt(value: Int) extends MySupportedType
final case class MyDouble(value: Double) extends MySupportedType
final case class MyListOfString(value: List[String]) extends MySupportedType
final case class MyListOfInt(value: List[Int]) extends MySupportedType

final case class Filter2(field: String, operator: String, variable: MySupportedType)

а затем использовать способ по умолчанию, чтобы извлечь значение копродукции или пользовательский кодек для MySupportedType

val config = ConfigFactory.parseString(
    """
    {
      field: "foo"
      operator: "bar"
      variable: {
        type: mylistofint
        value: []
      }
    }
    """)
  println(pureconfig.loadConfig[Filter2](config))
  // will print Right(Filter2(foo,bar,MyListOfInt(List())))

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

Вы можете сделать это поле ANY: Пример:

scala>   case class Filter(
     |   field: String,
     |   operator: String,
     |   variable: Any  // should support Int , Double , List[String], List[Int]
     |   )
defined class Filter

scala> Filter("anurag","data",List(12,34))
res5: Filter = Filter(anurag,data,List(12, 34))

scala> Filter("anurag","data",List(12.12,34.12))
res6: Filter = Filter(anurag,data,List(12.12, 34.12))

scala> Filter("anurag","data",List("Hello","Hii"))
res8: Filter = Filter(anurag,data,List(Hello, Hii))
Другие вопросы по тегам