groovekiller
groovekiller

Reputation: 1122

Parse JSON with unknown attributes names into a Case Class

I have the following JSON file to be parsed into a case class:

{
    "root": {
        "nodes": [{
                "id": "1",
                "attributes": {
                    "name": "Node 1",
                    "size": "3"
                }
            },
            {
                "id": "2",
                "attributes": {
                    "value": "4",
                    "name": "Node 2"
                }
            }
        ]
    }
}

The problem is that the attributes could have any value inside it: name, size, value, anything ...

At this moment I have defined my case classes:

case class Attributes(
  name: String,
  size: String,
  value: Sting
)
case class Nodes(
  id: String,
  attributes: Attributes
)
case class Root(
  nodes: List[Nodes]
)
case class R00tJsonObject(
  root: Root
)

Whats is the best way to deal with this scenario when I can receive any attribute ?

Currently I am using Json4s to handle son files.

Thanks!

Upvotes: 1

Views: 1507

Answers (1)

nondeterministic
nondeterministic

Reputation: 521

Your attributes are arbitrarily many and differently named, but it seems you can store them in a Map[String, String] (at least, if those examples are anything to go by). In this case, using circe-parser (https://circe.github.io/circe/parsing.html), you could simply use code along these lines in order to convert your JSON directly into a simple case-class:

import io.circe._, io.circe.parser._
import io.circe.generic.semiauto._

case class Node(id: String, attributes: Map[String,String])
case class Root(nodes: List[Node])

implicit val nodeDecoder: Decoder[Node] = deriveDecoder[Node]
implicit val nodeEncoder: Encoder[Node] = deriveEncoder[Node]

implicit val rootDecoder: Decoder[Root] = deriveDecoder[Root]
implicit val rootEncoder: Encoder[Root] = deriveEncoder[Root]

def myParse(jsonString: String) = {
  val res = parse(jsonString) match {
    case Right(json) => {
      val cursor = json.hcursor
      cursor.get[Root]("root")
    }
    case _ => Left("Wrong JSON!") 
  }
  println(res)
}

This snippet will print

Right(Root(List(Node(1,Map(name -> Node 1, size -> 3)), Node(2,Map(value -> 4, name -> Node 2)))))

on the console, for the JSON, you've given. (Assuming, the solution doesn't have to be in Json4s.)

Upvotes: 3

Related Questions