3

Am getting a JSON in

 {
    "segment": {
        "134": "34",
        "154": "342"
    }
}

all I am trying to do is map the keys as value i.e convert it into format like

    {
    "segment ": [{
        "segmentationStrategyId ": 134,
        "segmentID ": 34
    }, {
        "segmentationStrategyId ": 154,
        "segmentID ": 342
    }]
}

Tried using json4s parser but as key are diff I cannot map it to case class.

3 Answers 3

4

You can use spary.json to convert the json. If you use SBT you can include spray-json in your project with

libraryDependencies += "io.spray" %%  "spray-json" % "1.3.3"

Define the case class for your input and output.

case class InputJson(segment: Map[String, String])
case class OutputSegment(segmentationStrategyId: Int, segmentId: Int)
case class OutputJson(segment: List[OutputSegment])

Define the protocol through convert case class to json and json to case class

import spray.json._
object MyProtocol extends DefaultJsonProtocol {
  implicit val inputJsonFormat = jsonFormat1(InputJson.apply)
  implicit val outputSegmentFormat = jsonFormat2(OutputSegment.apply)
  implicit val outputJsonFormat = jsonFormat1(OutputJson.apply)
}

Input json:

val jsonString: String =
    """{
      |    "segment": {
      |        "134": "34",
      |        "154": "342"
      |    }
      |}""".stripMargin

parse the json String into JsValue

val jsonVal: JsValue = jsonString.parseJson

convert the JsValue into Case Class

val jsonInput: InputJson = jsonVal.convertTo[InputJson]

Now, you can map the Map[String,String] segment into OutputSegment format.

val outputSegments: List[OutputSegment] = jsonInput.segment.flatMap {
    case (key, value) => Try(OutputSegment(key.toInt, value.toInt)).toOption
  }.toList

create the OutputJson and get the equivalent Json String.

val outputJson: String = OutputJson(outputSegments).toJson.prettyPrint

Output Json String:

{
  "segment": [{
    "segmentationStrategyId": 134,
    "segmentId": 34
  }, {
    "segmentationStrategyId": 154,
    "segmentId": 342
  }]
}

Final full code sample:

import spray.json._
import scala.util.Try

object Test
  extends App {

  // case class
  case class InputJson(segment: Map[String, String])
  case class OutputSegment(segmentationStrategyId: Int, segmentId: Int)
  case class OutputJson(segment: List[OutputSegment])

  // protocol for json conversion
  object MyProtocol extends DefaultJsonProtocol {
    implicit val inputJsonFormat = jsonFormat1(InputJson.apply)
    implicit val outputSegmentFormat = jsonFormat2(OutputSegment.apply)
    implicit val outputJsonFormat = jsonFormat1(OutputJson.apply)
  }

  // input json
  val jsonString: String =
    """{
      |    "segment": {
      |        "134": "34",
      |        "154": "342"
      |    }
      |}""".stripMargin

  import MyProtocol._

  val jsonVal: JsValue = jsonString.parseJson

  val jsonInput: InputJson = jsonVal.convertTo[InputJson]

  val outputSegments: List[OutputSegment] = jsonInput.segment.flatMap {
    case (key, value) => Try(OutputSegment(key.toInt, value.toInt)).toOption
  }.toList

  val outputJson: String = OutputJson(outputSegments).toJson.prettyPrint

  println(outputJson)
}

Reference link: https://github.com/spray/spray-json

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

Comments

2

I am not familiar with json4s but managed to write this out quickly, might help:

import org.json4s._
import org.json4s.native.JsonMethods._

case class Segment(segmentationStrategyId: Int, segmentId: Int)

object Test {
  implicit val formats: DefaultFormats.type = DefaultFormats
  val json: String =
    """
      | {
      |    "segment": {
      |        "134": "34",
      |        "154": "342"
      |    }
      |}
    """.stripMargin

  def main(args: Array[String]): Unit = {
    val originalSegments = for {
      JObject(o) <- parse(json)
      JField("segment", JObject(segment))  <- o
    } yield segment

    val originalSegment = originalSegments.head
    val newSegments = originalSegment.map(
      s => Segment(s._1.toInt, s._2.extract[String].toInt)
    )
    println(newSegments)
  }
}

Prints out

List(Segment(134,34), Segment(154,342))

So you now have a list of case classes that you should be able to ransform into your JSON

Comments

0

It is much easier and faster with jsoniter-scala.

Add library dependency:

libraryDependencies ++= Seq(
  "com.github.plokhotnyuk.jsoniter-scala" %% "jsoniter-scala-core" % "0.29.2" % Compile, 
  "com.github.plokhotnyuk.jsoniter-scala" %% "jsoniter-scala-macros" % "0.29.2" % Provided // required only in compile-time
)

Define your data structures for input and output JSON:

case class Input(segment: mutable.LinkedHashMap[Int, Int])
case class OutputSegment(segmentationStrategyId: Int, segmentID: Int)
case class Output(segment: List[OutputSegment])

Generate codecs for your root case classes:

import com.github.plokhotnyuk.jsoniter_scala.macros._
import com.github.plokhotnyuk.jsoniter_scala.core._
implicit val inCodec: JsonValueCodec[Input] = JsonCodecMaker.make[Input](CodecMakerConfig())
implicit val outCodec: JsonValueCodec[Output] = JsonCodecMaker.make[Output](CodecMakerConfig())

Read input, convert to output and serialize it:

val fis = new FileInputStream("/tmp/input.json")
val input = try readFromStream(fis) finally fis.close()
val output = Output(input.segment.map(kv => OutputSegment(kv._1, kv._2)))
val fos = new FileOutputStream("/tmp/output.json")
try writeToStream(output, fos) finally fos.close()

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.