Using Circe to decode Json String

I have a Json string as

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

I have the following case class to decode json string.

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

Also, providers in above case class is optional, it may or may not be present in json string.

I want to decode this using circe to

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

I understand I need to use custom circe codec, but I am unable to do it, Can someone please help out on this.

2

3 Answers

You do not need a custom codec. You only need to need to configure the derived codec using circe-generic-extras.

So given:

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

You can:

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 } 

And then:

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()) // ) // ) 
8

Circe provides all Decoder instances you need except the one for TenantSettings since it's a custom type. Map and String are no problem.

circe-generic-extras or circe-derivation are very useful to generate Decoder instances for case classes. In this case you want to enable "defaults" in the config, so it falls back to the empty map instead of failing.

Here's the code:

// 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 -> ... 
5

This is what I did and worked for me

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) 

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

You Might Also Like