I'd like to generate all the possible JSONPath from a given case class itself and not an instance of the case class (preferably).
Simple case class with simple nesting:
case class Inner(innerA: String, innerB: String, innerC: String)
case class TestCase(a: String, b: String, inner: Inner)
For TestCase
, I'd like to produce (prefer declaration order but not a must):
root.a
root.b
root.inner
root.inner.innerA
root.inner.innerB
root.inner.innerC
Or something that'll easily transform into valid JSONPath. The purpose for this is so we can define several case class
in Scala and provide the user with a list of valid JSONPath that they can use to extract information.
Right now, there's no problem doing:
case class
to JSON- JSON to
case class
- Retrieve a value via JSONPath (as a string) from JSON by using
gatling
(see here) with something likeJsonPath.query(jsonPathString, jsonObj)
Using circe
it looks like I can do one step further and do root.inner.innerA
(see here) and get/set the value. However, I couldn't figure out how to produce the list of JSONPath using either circe
or gatling
(which feels like doing the reverse of what is being offered by those libraries).
An alternative I can think of is to recursively go through classOf[TestCase].getDeclaredFields
. Further searching produces:
- Scala. Get field names list from case class
- Scala 2.10 reflection, how do I extract the field values from a case class
However, it looks like I still need to recursively go through each field and see if there's anything nested. Is this the best approach?
Samples:
- Instance of case class :
TestCase(a = "alpha", "beta", inner = Inner(innerA = "innerAlpha", innerB = "innerBeta", innerC = "foo"))
- JSON produced of above:
{"a":"alpha","b":"beta","inner":{"innerA":"innerAlpha","innerB":"innerBeta","innerC":"foo"}}
- JSONPath evaluator : http://jsonpath.com/ (e.g.
$.inner.innerA
)
Current solution(?):
def recursive(members: MemberScope, parent: String): Unit = {
members.foreach { member =>
member match {
case m: MethodSymbol if m.isCaseAccessor =>
println(s"$parent.${m.name}")
recursive(m.returnType.members, s"$parent.${m.name}")
case _ =>
}
}
}
recursive(typeOf[TestCase].members, "$")
Which produces:
$.inner
$.inner.innerC
$.inner.innerB
$.inner.innerA
$.b
$.a
EDIT: Supposedly shapeless is able to do this but I haven't quite figured it out.
Aucun commentaire:
Enregistrer un commentaire