Issue with Serialising Array[Byte] lift-json

32 views
Skip to first unread message

kay archer

unread,
May 11, 2017, 7:02:24 AM5/11/17
to Lift

I am having issues serialising / deserialising a case class with an Array[Byte] field. I am using lift-json and have created a case class as below:

case class TestNestedClass(matchKey: Array[Byte],
                      matchId: Long,
                      name: String) 

I am then using the Wrapper functionality to attempt to create from JSON and to JSON methods.

case class TestNestedClassWrapper(tnc: TestNestedClass) {
  implicit val formats: Formats = DefaultFormats + ArrayByteSerializer

  def toJson: String = {
    val json = Extraction.decompose(this)
    pretty(render(json))
  }
}

case object TestNestedClassWrapper {
  implicit val formats: Formats = DefaultFormats + ArrayByteSerializer

  def apply(jsonString: String): TestNestedClassWrapper = {
    read[TestNestedClassWrapper](jsonString)
  }
}

The extra custom serialiser for ArrayBytes is as follows:

object ArrayByteSerializer extends Serializer[Array[Byte]] {

  private val Class = classOf[Array[Byte]]

  def deserialize(implicit format: Formats): PartialFunction[(TypeInfo, JValue), Array[Byte]] = {
    case (TypeInfo(Class, _), json) => json match {
      case JString(iv) =>  Bytes.toBytes(iv)
      case value => throw new MappingException("Can't convert " + value + " to " + Class)
    }
  }
  def serialize(implicit format: Formats): PartialFunction[Any, JValue] = {
    case s: Array[Byte] => JString(Bytes.toString(s))
  }
}

When I test these methods, it seems that they are not working correctly. The class TestNestedClass does not show up at all:

  val test1 = TestNestedClass(Bytes.toBytes("1234"),1234,"test1")
  val testNestedClassWrapper = TestNestedClassWrapper(test1)
  val json = testNestedClassWrapper.toJson
  println(json)

RES

{
  "tnc":{

  }
}

If I remove the Array[Byte] field I can serialise the case class successfully:

case class TestNestedClass2(matchId: Long,
                           name: String) 

RES

{
  "tnc":{
    "matchId":1234,
    "name":"test1"
  }
}

Is there any reason, that my ArrayByteSerializer is not working?

Thanks!



Matt Farmer

unread,
May 11, 2017, 8:30:17 AM5/11/17
to Lift
I'm not sure what library you're pulling your Bytes class from, so it's hard for me to replicate your code examples exactly. That said, I think we have built in support for Array[Byte]:

@ case class TestNestedClass(matchKey: Array[Byte],
                        matchId: Long,
                        name: String)
defined class TestNestedClass
@ TestNestedClass(Array(58, 23), 123, "Bacon")
res4: TestNestedClass = TestNestedClass(Array(58, 23), 123L, "Bacon")
@ implicit val formats = DefaultFormats
formats: DefaultFormats.type = net.liftweb.json.DefaultFormats$@383b3357
@ import Extraction._
import Extraction._
@ decompose(res4)
res7: JValue = JObject(List(JField("matchKey", JArray(List(JInt(58), JInt(23)))), JField("matchId", JInt(123)), JField("name", JString("Bacon"))))
@ res7.extract[TestNestedClass]
res8: TestNestedClass = TestNestedClass(Array(58, 23), 123L, "Bacon")

Can you perhaps try without your custom serializer?

--
--
Lift, the simply functional web framework: http://liftweb.net
Code: http://github.com/lift
Discussion: http://groups.google.com/group/liftweb
Stuck? Help us help you: https://www.assembla.com/wiki/show/liftweb/Posting_example_code

---
You received this message because you are subscribed to the Google Groups "Lift" group.
To unsubscribe from this group and stop receiving emails from it, send an email to liftweb+u...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

kay archer

unread,
May 11, 2017, 1:26:58 PM5/11/17
to Lift
Hey Matt, 

Thanks for the answer. The Bytes class is under the HBase Client module.

import org.apache.hadoop.hbase.util.Bytes.

If I only use Default Formats I get nothing returned back as in the case with the custom serializer:

case class TestClassWrapper(tc: TestClass) {

implicit val formats: Formats = DefaultFormats

  def toJson: String = {
val json = Extraction.decompose(this)
pretty(render(json))
}
}

case object TestClassWrapper {

implicit val formats: Formats = DefaultFormats

  def apply(jsonString: String): TestClassWrapper = {
read[TestClassWrapper](jsonString)
}
}

Also as a question, how did you define the test cases you used for TestNestedClass

i.e. this: TestNestedClass(Array(58, 23), 123, "Bacon")

What are you defining the byte representation??

Thanks!

Matt Farmer

unread,
May 15, 2017, 8:39:23 AM5/15/17
to Lift
Hi there,

If you look at the start of my code snippet, you'll see the case class definition:




Matt Farmer

unread,
May 15, 2017, 8:41:25 AM5/15/17
to Lift
Sorry, hit send too early.

The case class definition is here:

@ case class TestNestedClass(matchKey: Array[Byte],
                        matchId: Long,
                        name: String)

So it should be pretty straightforward to get working?

What version of Lift are you using?
Reply all
Reply to author
Forward
0 new messages