user1052610
user1052610

Reputation: 4719

Transforming Scala case class into JSON

I have two case classes. The main one, Request, contains two maps. The first map has a string for both key and value. The second map has a string key, and value which is an instance of the second case class, KVMapList.

case class Request (var parameters:MutableMap[String, String] = MutableMap[String, String](), var deps:MutableMap[String, KVMapList] = MutableMap[String, KVMapList]())

case class KVMapList(kvMap:MutableMap[String, String], list:ListBuffer[MutableMap[String, String]])

The requirement is to transform Request into a JSON representation. The following code is trying to do this:

import com.fasterxml.jackson.annotation.PropertyAccessor
import com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapper
import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility
import com.fasterxml.jackson.databind.ObjectMapper

def test(req:Request):String {
  val mapper = new ObjectMapper() with ScalaObjectMapper
  mapper.setVisibility(PropertyAccessor.ALL,  Visibility.ANY)
  var jsonInString: String = null
  try {
    jsonInString = mapper.writeValueAsString(request)
  }
  catch {
    =case e: IOException => {
      e.printStackTrace
   }
  jsonString
}

This however is not working. Even when the Request class is populated, the output is :

{"parameters":{"underlying":{"some-value":""},"empty":false,"traversableAgain":true},"deps":{"sizeMapDefined":false,"empty":false,"traversableAgain":true}}

Using the JSON object mapper with corresponding Java classes is straightforward, but have not yet got it working in Scala. Any assistance is very much appreciated.

Upvotes: 4

Views: 15437

Answers (2)

flavian
flavian

Reputation: 28511

Jackson is more of a bad old memory in Scala to some degree. You should use a native Scala library for JSON processing, particularly one really good at compile time derivation of JSON serializers, such as circe.

I'm aware this doesn't directly answer your question, but after using circe I would never go back to anything else.

import io.circe.generic.auto._
import io.circe.parser._
import io.circe.syntax._

val req = new Request(...)
val json = req.asJson.noSpaces
val reparsed = decode[Request](json)

On a different note, using mutable maps inside case classes is as non-idiomatic as it gets, and it should be quite trivial to implement immutable ops for your maps using the auto-generated copy method.

case class Request(parameters: Map[String, String] {
  def +(key: String, value: String): Request = {
    this.copy(parameters = parameters + (key -> value))
  }
}

You should really avoid mutability wherever possible, and it looks like avoiding it here wouldn't be much work at all.

Upvotes: 11

Dima
Dima

Reputation: 40510

I am not sure what this ScalaObjectMapper does, doesn't look like it is useful. If you add mapper.registerModule(DefaultScalaModule) in the beginning, it should work ... assuming that by MutableMap you mean mutable.Map, and not some sort of home-made class (because, if you do, you'd have to provide a serializer for it yourself).

(DefaultScalaModule is in jackson-module-scala library. Just add it to your build if you don't already have it).

Upvotes: 1

Related Questions