0

Using the Scala play library I'm attempting to parse the string :

  var str = "{\"payload\": \"[{\\\"test\\\":\\\"123\\\",\\\"tester\\\":\\\"456\\\"}," +
    "{\\\"test1\\\":\\\"1234\\\",\\\"tester2\\\":\\\"4567\\\"}]\"}";

into a list of Payload classes using code below :

import play.api.libs.json._

object TestParse extends App {
  
  case class Payload(test : String , tester : String)
  object Payload {
    implicit val jsonFormat: Format[Payload] = Json.format[Payload]
  }

  var str = "{\"payload\": \"[{\\\"test\\\":\\\"123\\\",\\\"tester\\\":\\\"456\\\"}," +
    "{\\\"test1\\\":\\\"1234\\\",\\\"tester2\\\":\\\"4567\\\"}]\"}";

  println((Json.parse(str) \ "payload").as[List[Payload]])

}

build.sbt :

name := "akka-streams"

version := "0.1"

scalaVersion := "2.12.8"

lazy val akkaVersion = "2.5.19"
lazy val scalaTestVersion = "3.0.5"

libraryDependencies ++= Seq(
  "com.typesafe.akka" %% "akka-stream" % akkaVersion,
  "com.typesafe.akka" %% "akka-stream-testkit" % akkaVersion,
  "com.typesafe.akka" %% "akka-testkit" % akkaVersion,
  "org.scalatest" %% "scalatest" % scalaTestVersion
)

// https://mvnrepository.com/artifact/com.typesafe.play/play-json
libraryDependencies += "com.typesafe.play" %% "play-json" % "2.10.0-RC6"

It fails with exception :

Exception in thread "main" play.api.libs.json.JsResultException: JsResultException(errors:List((,List(JsonValidationError(List("" is not an object),WrappedArray())))))

Is the case class structure incorrect ?

I've updated the code to :

import play.api.libs.json._

object TestParse extends App {

  import TestParse.Payload.jsonFormat
  object Payload {
    implicit val jsonFormat: Format[RootInterface] = Json.format[RootInterface]
  }
  case class Payload (
                       test: Option[String],
                       tester: Option[String]
                     )

  case class RootInterface (
                             payload: List[Payload]
                           )

  val str = """{"payload": [{"test":"123","tester":"456"},{"test1":"1234","tester2":"4567"}]}"""

  println(Json.parse(str).as[RootInterface])

}

which returns error :

No instance of play.api.libs.json.Format is available for scala.collection.immutable.List[TestParse.Payload] in the implicit scope (Hint: if declared in the same file, make sure it's declared before) implicit val jsonFormat: Format[RootInterface] = Json.format[RootInterface]

4
  • 1
    There's too much \ isn't it? And actually too much quoted as well. Commented Oct 6, 2022 at 17:09
  • 1
    Change your JSON string to """...""" syntax to avoid all the escapes. Commented Oct 6, 2022 at 17:10
  • @GaëlJ please see question update. Commented Oct 6, 2022 at 19:54
  • 1
    The error means you need a JSON format for Payload, to create a JSON format for RootInterface. With that change the program will print RootInterface(List(Payload(Some(123),Some(456)), Payload(None,None))) as test1 and tester2 are not members of Payload. Commented Oct 7, 2022 at 6:54

1 Answer 1

0

This performs the task but there are cleaner solutions :

import akka.actor.ActorSystem
import akka.stream.scaladsl.{Flow, Sink, Source}
import org.scalatest.Assertions._
import spray.json.{JsObject, JsonParser}

import scala.concurrent.Await
import scala.concurrent.duration.DurationInt

object TestStream extends App {
  implicit val actorSystem = ActorSystem()
  val mapperFlow = Flow[JsObject].map(x => {
    x.fields.get("payload").get.toString().replace("{", "")
      .replace("}", "")
      .replace("[", "")
      .replace("]", "")
      .replace("\"", "")
      .replace("\\", "")
      .split(":").map(m => m.split(","))
      .toList
      .flatten
      .grouped(4)
      .map(m => Test(m(1), m(3).toDouble))
      .toList
  })

  val str = """{"payload": [{"test":"123","tester":"456"},{"test":"1234","tester":"4567"}]}"""
  case class Test(test: String, tester: Double)

val graph = Source.repeat(JsonParser(str).asJsObject())
  .take(3)
  .via(mapperFlow)
  .mapConcat(identity)
  .runWith(Sink.seq)

  val result = Await.result(graph, 3.seconds)

  println(result)
  assert(result.length == 6)
  assert(result(0).test == "123")
  assert(result(0).tester == 456 )
  assert(result(1).test == "1234")
  assert(result(1).tester == 4567 )
  assert(result(2).test == "123")
  assert(result(2).tester == 456 )
  assert(result(3).test == "1234")
  assert(result(3).tester == 4567 )

}

Alternative, ioiomatic Scala answers are welcome.

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.