1

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!

4
  • 2
    In that case why not just keep it as a map like Map[String, Any] or a JObject from Json4s? Commented Feb 28, 2018 at 14:49
  • Using classes allows me to create different methods to handle the data. I also need to modify data which is easier when using classes (Object are immutable) Commented Feb 28, 2018 at 14:56
  • There are immutable Maps in Scala and you can still create methods to handle the data if it's in a map. You need to know what fields are going to be in your json in order to make it into a case class. If they will vary you can always make them Option fields but you still need to know the name of the properties. Commented Feb 28, 2018 at 15:15
  • That's the case, I already have a case class with options. But I do not know the name for every property. I have this done with JObject, but I want to convert to case classes. I saw something about dynamic case classes, but is not working Commented Feb 28, 2018 at 15:37

1 Answer 1

3

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.)

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.