1

Part of my config contains arbitrary JSON. I want to deserialize that JSON as a JValue for later processing.

However, ConfigSource.load complains that the type key is not found.

Test code:

import org.json4s.JsonAST.JValue
import pureconfig.ConfigReader.Result
import pureconfig._
import pureconfig.generic.auto._

object PureConfig2JValue extends App {
  case class Config(json: JValue)

  val source: ConfigObjectSource = ConfigSource.string("{ \"json\": { \"test\": \"test\" } }")

  val loadedSource: Result[Config] = source.load[Config]

  println(loadedSource)
}

Output:

Left(ConfigReaderFailures(ConvertFailure(KeyNotFound(type,Set()),None,json),List()))

How can I get PureConfig to deserialize to a JValue?

Update:

I adapted Gagandeep's answer to my older version of PureConfig:

implicit val configReader: ConfigReader[JValue] = new ConfigReader[JValue] {
  override def from(cur: ConfigCursor): Either[ConfigReaderFailures, JValue] =
    cur.asString match {
      case Right(jsonString: String) => Right(parse(jsonString))
      case Left(configReaderFailures: ConfigReaderFailures) => Left(configReaderFailures)
    }
}

It changed the error message, which I take to be progress:

Left(ConfigReaderFailures(ConvertFailure(WrongType(OBJECT,Set(STRING)),None,json),List()))

It seems PureConfig expected a String somewhere but instead found and Object. I'm not sure where the disconnect lies. I'm using cur.asString to ensure the item is returned as its appropriate type.

Update 2:

This probably isn't the most robust solution, but it works for my test case:

implicit val configReader: ConfigReader[JValue] = new ConfigReader[JValue] {
  override def from(cur: ConfigCursor): Either[ConfigReaderFailures, JValue] = {
    Right(
      // Parse PureConfig-rendered JSON.
      parse(
        // Render config as JSON.
        cur.value.render(ConfigRenderOptions.concise.setJson(true))
      )
    )
  }
}
crenshaw-dev
  • 7,504
  • 3
  • 45
  • 81
  • BEWARE: Json4s is [vulnerable under DoS/DoW attacks](https://github.com/json4s/json4s/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+denial)! – Andriy Plokhotnyuk May 06 '20 at 05:52

1 Answers1

2

JValue is not a class, tuple, case class or a sealed trait, hence macro cannot produce automatic derivation for it. Defining a reader for it should help.

import org.json4s._
import org.json4s.native.JsonMethods._

implicit val configReader = new ConfigReader[JValue] {
    override def from(cur: ConfigCursor): Result[JValue] = cur.asString.map(parse)
}
Gagandeep Kalra
  • 1,034
  • 14
  • 13
  • Thanks, looks like a great answer! I updated my question to show a new roadblock I hit after trying your code. Please let me know if you see any obvious solutions. – crenshaw-dev Nov 08 '19 at 15:24
  • Accepted since this set me on the right path. The code I used is in the updated question. – crenshaw-dev Nov 08 '19 at 15:47