Last active
September 21, 2022 21:38
-
-
Save jgogstad/f2833bd076268d6cf902973764b0a099 to your computer and use it in GitHub Desktop.
YAML -> JSON -> HOCON -> CaseClass -> HOCON -> JSON -> YAML using Json4s, moultingyaml and pureconfig
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import org.json4s._ | |
import org.json4s.JsonAST.{JArray, JNull, JObject, JNumber} | |
import net.jcazevedo.moultingyaml._ | |
import net.jcazevedo.moultingyaml.DefaultYamlProtocol._ | |
object YamlJsonProtocol extends CollectionFormats { | |
implicit object JValueYamlFormat extends YamlFormat[JValue] { | |
override def write(jv: JValue): YamlValue = jv match { | |
case JDouble(n) => YamlNumber(n) | |
case JDecimal(n) => YamlNumber(n) | |
case JLong(n) => YamlNumber(n) | |
case JInt(n) => YamlNumber(n) | |
case JString(s) => YamlString(s) | |
case a: JArray => seqFormat[JValue].write(a.arr) | |
case o: JObject => mapFormat[String, JValue].write(o.obj.toMap) | |
case JBool(b) => YamlBoolean(b) | |
case JNull => YamlNull | |
case x => serializationError(s"Unexpected JSON value: $x") | |
} | |
override def read(yv: YamlValue): JValue = yv match { | |
case x: YamlNumber => x.value.toBigIntExact().map(JInt).getOrElse(JDecimal(x.value)) | |
case YamlString(s) => JString(s) | |
case a: YamlArray => JArray(listFormat[JValue].read(a)) | |
case o: YamlObject => JObject(mapFormat[String, JValue].read(o).toList) | |
case YamlBoolean(b) => JBool(b) | |
case YamlNull => JNull | |
case x => deserializationError(s"Unexpected YAML value: $x") | |
} | |
} | |
implicit object JObjectYamlFormat extends YamlFormat[JObject] { | |
override def write(jso: JObject): YamlValue = jso.toYaml | |
override def read(yv: YamlValue): JObject = yv.convertTo[JValue] match { | |
case jso: JObject => jso | |
case x => deserializationError(s"Expected YAML object, got: $x") | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import com.tapad.platform.service.model.kubernetes.YamlJsonProtocol._ | |
import com.typesafe.config.{ConfigFactory, ConfigParseOptions, ConfigRenderOptions, ConfigSyntax} | |
import net.jcazevedo.moultingyaml._ | |
import org.json4s._ | |
import org.json4s.jackson.JsonMethods._ | |
import org.scalatest.{FlatSpec, Matchers} | |
import pureconfig._ | |
class YamlJsonProtocolSpec extends FlatSpec with Matchers { | |
it should "map json to yaml" in { | |
val json = | |
parse("""{ "foo": "bar", "numbers": { "some": [{"number": 1},{"host": "some-host", "port": 8080 }, 3] }}""") | |
json.toYaml.prettyPrint shouldBe | |
"""foo: bar | |
|numbers: | |
| some: | |
| - number: 1 | |
| - host: some-host | |
| port: 8080 | |
| - 3 | |
|""".stripMargin | |
} | |
it should "map yaml to json" in { | |
val yaml = """foo: bar | |
|numbers: | |
| some: | |
| - number: 1 | |
| - host: some-host | |
| port: 8080 | |
| - 3 | |
|""".stripMargin.parseYaml | |
compact(yaml.convertTo[JValue]) shouldBe """{"numbers":{"some":[{"number":1},{"host":"some-host","port":8080},3]},"foo":"bar"}""" | |
} | |
it should "map case-class -> hocon -> json -> yaml" in { | |
val hocon = | |
"""one = foo | |
|camel-case = 42 | |
""".stripMargin | |
val caseClass = pureconfig.loadConfigOrThrow[HoconCamelCase](ConfigFactory.parseString(hocon)) | |
val json = parse(ConfigWriter[HoconCamelCase].to(caseClass).render(ConfigRenderOptions.concise())) | |
val yaml = json.toYaml | |
yaml.prettyPrint shouldBe | |
"""camel-case: 42 | |
|one: foo | |
|""".stripMargin | |
} | |
it should "map yaml -> json -> hocon -> case-class" in { | |
val yaml = """camel-case: 42 | |
|one: foo | |
|""".stripMargin.parseYaml | |
val json = compact(yaml.convertTo[JValue]) | |
val jsonSyntax = ConfigParseOptions.defaults().setSyntax(ConfigSyntax.JSON) | |
val caseClass = pureconfig.loadConfigOrThrow[HoconCamelCase](ConfigFactory.parseString(json, jsonSyntax)) | |
caseClass.camelCase shouldBe 42 | |
caseClass.one shouldBe "foo" | |
} | |
it should "map hocon to json to yaml and preserve camelCase" in { | |
val hocon = | |
"""one = foo | |
|camelCase = 42 | |
""".stripMargin | |
implicit val camelCase = ProductHint[HoconCamelCase](ConfigFieldMapping(CamelCase, CamelCase)) | |
val caseClass = pureconfig.loadConfigOrThrow[HoconCamelCase](ConfigFactory.parseString(hocon)) | |
val json = parse(ConfigWriter[HoconCamelCase].to(caseClass).render(ConfigRenderOptions.concise())) | |
val yaml = json.toYaml | |
yaml.prettyPrint shouldBe | |
"""camelCase: 42 | |
|one: foo | |
|""".stripMargin | |
} | |
} | |
case class HoconCamelCase(one: String, camelCase: Int) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment