Назначить любой 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))