Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
502 views
in Technique[技术] by (71.8m points)

Scala: Recursive Case Class with logical operators as children

I'm trying to create a case class for the below Json object:

{
    "or": [
        {
            "and": [
                {
                    "ids": [
                        123
                    ]
                },
                {
                    "ids": [
                        234
                    ]
                }
            ]
        }
    ],
    "not": {
        "ids": [
            789
        ]
    }
}

We can have multiple nested or/and/not with "ids" as the leaf node.

I could bring up the case classes as below, but the problem is when I try to implement reads & writes for json serialisation/deserialisation.

sealed trait Tree

case class Or(node: Tree*) extends Tree
case class And(node: Tree*) extends Tree
case class Not(node: Tree) extends Tree

case class Leaf(ids: Seq[Int]

I'm using the below implicit override method:

object Tree {
  implicit lazy val treeReads: Reads[Tree] =
   (__.lazyRead(Or.orReads).map(x => x:Tree) orElse __.lazyRead(And.andReads).map(x => x:Tree) orElse __.lazyRead(Not.notReads).map(x => x:Tree)
orElse __.lazyRead(Lead.leafReads).map(x => x:Tree))

  implicit lazy val treeWrites: Writes[Tree] =
  {
    case or: Or => Json.toJson(or)(Or.orWrites)
    case and: And => Json.toJson(and)(And.andWrites)
    case not: Not => Json.toJson(not)(Not.notWrites)
    case at: Leaf => Json.toJson(at)(Leaf.leafWrites)
  }
}

But the issue is I always get the Json as below:

{
    "leaf": [
        {
            "ids": [
                123
            ]
        }
    ]
}

How can I replace the "leaf" key in the entire json tree structure with appropriate case class names ("or", "and", "not")?

question from:https://stackoverflow.com/questions/66065730/scala-recursive-case-class-with-logical-operators-as-children

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Basically you have it all correct. The only thing is that your json is not of the form of you data. The following json:

{
    "and": [
        {
            "or": [
                {
                    "and": [
                        {
                            "ids": [
                                123
                            ]
                        },
                        {
                            "ids": [
                                234
                            ]
                        }
                    ]
                }
            ]
        },
        {
            "not": {
                "ids": [
                    789
                ]
            }
        }
    ]
}

Will provide with the same code you wrote:

And(List(Or(List(And(List(Leaf(List(123)), Leaf(List(234)))))), Not(Leaf(List(789)))))

And the following json:

{
    "or": [
        {
            "and": [
                {
                    "ids": [
                        123
                    ]
                },
                {
                    "ids": [
                        234
                    ]
                }
            ]
        },
        {
            "not": {
                "ids": [
                    789
                ]
            }
        }
    ]
}

will provide:

Or(List(And(List(Leaf(List(123)), Leaf(List(234)))), Not(Leaf(List(789)))))

Which is what you expect, I guess.

Code run at Scastie


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

2.1m questions

2.1m answers

60 comments

57.0k users

...