Wojciech Durczyński
Wojciech Durczyński

Reputation: 2637

Which JSON serialization library would fit to the following case?

I've got following case: I'd like to serialize Scala case classes that extend parent class with var of type java.util.UUID. Serialization of this case classes should happen without any configuration of them - no annotations and definition of custom formats. Any serialization hints may be situated in parent class.

I tried sjson, but Reflection based serialization can't serialize UUID types and type based serialization forces me to define formats for every case class. Which json serialization library would best fit this case?

Upvotes: 2

Views: 1525

Answers (4)

Andy
Andy

Reputation: 5218

Try the XStream library which includes JSON support. I have used this successfully in a few projects. It has a number of default converters, including one for java.util.UUID. A full list of default converters is located here: http://x-stream.github.io/converters.html.

A brief tutorial on using XStream for JSON reading and writing is located here: http://x-stream.github.io/json-tutorial.html. The tutorial code is written for Java but it should work just the same for Scala since reflection is being used behind the scenes.

Keep in mind that serializing and then deserializing arbitrary graphs of objects is not always possible with this library. In particular, loops in your data cannot be handled, i.e. your data must be a purely hierarchical tree. This is a reasonable limitation given the intentions of the JSON format.

Referenced links:
XStream JSON tutorial: http://x-stream.github.io/json-tutorial.html
XStream default converters: http://x-stream.github.io/converters.html

Upvotes: 2

eivindw
eivindw

Reputation: 1959

You could try jerkson: https://github.com/codahale/jerkson

Its working good for my use, but that is mostly list/map structures. Would not be surprised if it supports your needs though..

Edit: Tried it with the following example (inspired by the lift example in another answer). Seems to work fine.

import java.util.UUID
import com.codahale.jerkson.Json
import org.scalatest.FunSuite

sealed abstract class Parent {
   def uuid: UUID
}

case class Foo(uuid: UUID, name: String) extends Parent

class TmpJsonTest extends FunSuite {
   test("Json case class serialize") {
      val f = Foo(UUID.randomUUID, "foo")
      val ser = Json.generate(f)
      println(ser)
      val f2 = Json.parse[Foo](ser)
      assert(f === f2)
   }
}

Upvotes: 2

Joni
Joni

Reputation: 2789

Here's one solution with Lift JSON.

import java.util.UUID
import net.liftweb.json._
import net.liftweb.json.JsonAST._
import net.liftweb.json.JsonDSL._
import net.liftweb.json.Serialization._

sealed abstract class Parent {
  def uuid: UUID
}
case class Foo(uuid: UUID, name: String) extends Parent

object UUIDTest extends Application {
  implicit val formats =  Serialization.formats(NoTypeHints) + new UUIDSerializer

  val f = Foo(UUID.randomUUID, "foo")
  val ser = write(f)
  println(ser)
  val f2 = read[Foo](ser)
  assert(f == f2)

  // Special serializer for UUID type
  class UUIDSerializer extends Serializer[UUID] {
    private val Class = classOf[UUID]

    def deserialize(implicit format: Formats): PartialFunction[(TypeInfo, JValue), UUID] = {
      case (TypeInfo(Class, _), json) => json match {
        case JObject(JField("mostSig", JInt(m)) :: JField("leastSig", JInt(l)) :: Nil) =>
          new UUID(m.longValue, l.longValue)
        case x => throw new MappingException("Can't convert " + x + " to UUID")
      }
    }

    def serialize(implicit format: Formats): PartialFunction[Any, JValue] = {
      case x: UUID =>
        ("mostSig" -> x.getMostSignificantBits) ~ ("leastSig" -> x.getLeastSignificantBits)
    }
  }
}

It prints:

{"uuid":{"mostSig":-8054689529719995935,"leastSig":-5722404370736228056},"name":"foo"}'

Another solution which uses a custom serializer for Parent type.

sealed abstract class Parent {
  var uuid: UUID = UUID.randomUUID
}
case class Foo(name: String) extends Parent

object UUIDTest extends Application {
  implicit val formats = 
    Serialization.formats(NoTypeHints) + new ParentSerializer

  val f = Foo("foo")
  val ser = write(f)
  println(ser)
  val f2 = read[Foo](ser)
  assert(f == f2)

  // Special serializer for Parent type
  class ParentSerializer extends Serializer[Parent] {
    def deserialize(implicit format: Formats): PartialFunction[(TypeInfo, JValue), Parent] = {
      case (t@TypeInfo(cl, _), json) if (classOf[Parent].isAssignableFrom(cl)) => 
        val x = Extraction.extract(json, t)(DefaultFormats).asInstanceOf[Parent]
        x.uuid = (for { 
          JField("mostSig", JInt(m))  <- json
          JField("leastSig", JInt(l)) <- json 
        } yield new UUID(m.longValue, l.longValue)).head
        x
    }

    def serialize(implicit format: Formats): PartialFunction[Any, JValue] = {
      case x: Parent =>
        Extraction.decompose(x)(DefaultFormats) ++ 
        JField("mostSig", x.uuid.getMostSignificantBits) ++ 
        JField("leastSig", x.uuid.getLeastSignificantBits)
    }
  }
}

Upvotes: 4

Syl
Syl

Reputation: 2783

If the type is important, you should take a look at YAML.

http://www.google.fr/search?q=java+yaml

It's a subset of json with improved stuff, like variable typing.

Upvotes: 2

Related Questions