Использование Circe для декодирования Json String - PullRequest
0 голосов
/ 18 февраля 2020

У меня есть строка Json как

val configInfo =   {
      "car": {
        "requesters": {
          "request1": "key1",
          "request2": "key2"
        },
        "provider": {
          "request1": "key3",
          "request2": "key4"
        }
      },
      "truck": {
        "requesters": {
          "request1": "key2",
          "request2": "key3"
        },
        "provider": {
          "request1": "key2",
          "request2": "key3"
        }
      }
    }

У меня есть следующий класс case для декодирования json строки.

final case class TenantSettings(requesters: Map[String, String], provider: Map[String, String] = Map.empty)

Также провайдеры в вышеприведенном классе case необязательно, он может присутствовать или не присутствовать в строке json.

Я хочу расшифровать это с помощью circe до

val value = decode[Map[String, TenantSettings]](configInfo)

Я понимаю, что мне нужно использовать пользовательский код Circe c , но я не могу этого сделать. Может кто-нибудь помочь с этим?

Ответы [ 3 ]

2 голосов
/ 18 февраля 2020

Вам не нужен пользовательский код c. Вам нужно только сконфигурировать производный код c, используя circe-generi c -extras .

Так дано:

val configInfo =
    """{
        "car": {
          "requesters": {
            "request1": "key1",
            "request2": "key2"
          },
          "provider": {
            "request1": "key3",
            "request2": "key4"
          }
        },
        "truck": {
          "requesters": {
            "request1": "key2",
            "request2": "key3"
          },
          "provider": {
            "request1": "key2",
            "request2": "key3"
          }
        },
        "blah": {
          "requesters": {
            "request1": "key2"
          }
        }
      }"""

Вы можете:

import io.circe.Decoder
import io.circe.generic.extras.Configuration
import io.circe.generic.extras.semiauto.deriveConfiguredDecoder

final case class TenantSettings(requesters: Map[String, String], provider: Map[String, String] = Map.empty)
object TentantSettings {
  private implicit final val customConfig: Configuration = Configuration.default.withDefaults
  implicit final val TenantSettingsDecoder: Decoder[TenantSettings] = deriveConfiguredDecoder
}

А затем:

io.circe.parser.decode[Map[String, TenantSettings]](configInfo)
// res: Either[io.circe.Error, Map[String, TenantSettings]] = Right(
//   Map(
//     "car" -> TenantSettings(Map("request1" -> "key1", "request2" -> "key2"), Map("request1" -> "key3", "request2" -> "key4")),
//     "truck" -> TenantSettings(Map("request1" -> "key2", "request2" -> "key3"), Map("request1" -> "key2", "request2" -> "key3")),
//     "blah" -> TenantSettings(Map("request1" -> "key2"), Map())
//   )
// )
1 голос
/ 18 февраля 2020

Circe предоставляет все необходимые экземпляры Decoder, кроме одного для TenantSettings, поскольку это пользовательский тип. Map и String не проблема.

circe-generic-extras или circe-derivation очень полезны для генерации Decoder экземпляров для классов дел. В этом случае вы хотите включить «по умолчанию» в конфигурации, поэтому вместо сбоя он возвращается к пустой карте.

Вот код:

// you need circe-core, circe-parser and circe-generic-extras as dependencies
import io.circe._
import io.circe.parser.decode
import io.circe.generic.extras.Configuration
import io.circe.generic.extras.semiauto._

val configInfo = """{
    "car": {
      "requesters": {
        "request1": "key1",
        "request2": "key2"
      },
      "provider": {
        "request1": "key3",
        "request2": "key4"
      }
    },
    "truck": {
      "requesters": {
        "request1": "key2",
        "request2": "key3"
      },
      "provider": {
        "request1": "key2",
        "request2": "key3"
      }
    }
  }
  """

final case class TenantSettings(
  requesters: Map[String, String],
  provider: Map[String, String] = Map.empty
)
object TenantSettings {
  implicit private val derivationConfig: Configuration = Configuration.default.withDefaults

  implicit val decodeTenantSettings: Decoder[TenantSettings] = deriveConfiguredDecoder
}

val value = decode[Map[String, TenantSettings]](configInfo)
println(value) // Right(Map(car -> TenantSettings(Map(request1 -> key1, request2 -> ...
0 голосов
/ 18 февраля 2020

Это то, что я сделал и работал для меня

implicit val decodeTenantSetting: Decoder[TenantSettings] = new Decoder[TenantSettings] {
      final def apply(c: HCursor): Decoder.Result[TenantSettings] =
        for {
          requesters <- c.downField("requesters").as[Map[String, String]]
        } yield {
          TenantSettings(requesters)
        }
    }

val abc = decode[Map[String, TenantSettings]](configInfo)
...