0

How can I unpickle an object with a field that might miss (and use an null) in that case?

scala> case class Person(name:String=null,age:Int)
defined class Person
scala> import scala.pickling.Defaults._, scala.pickling.json._
scala> val p2 = JSONPickle("""{"age":2}""").unpickle[Person]
scala.pickling.PicklingException: No field 'name' when unpickling, tag Person, fields were Map(age -> 2.0)

I need this in order to unpickle a string came from browser that is also missing the type field, so I will not be able to use an Option/Some/None type.

raisercostin
  • 8,777
  • 5
  • 67
  • 76

2 Answers2

1

Just declare it having type Option[String], like this:

case class Person(name: Option[String], age: Int)

Option[T] is the idiomatic Scala way of handling values which otherwise (e.g. in Java) could be null

Denis Mikhaylov
  • 2,035
  • 21
  • 24
  • Unfortunately this was not an option since the web browser will need to create the json for Person and knowing the pickling internal format might be a little to much to ask. I was hoping that a formatter to plain simple json exists. – raisercostin Jul 29 '15 at 05:11
  • If you browser just don't send `name` field it will be treated as `None`. – Denis Mikhaylov Jul 30 '15 at 06:03
  • I tested with Option[String] and it seems that it still fails if the name is missing. Besides what string should come from browser to have a Some("name1") as name? The browser should send something like { "$type": "Person", "name": { "$type": "scala.Some[java.lang.String]", "x": "name1" }, "age": 1 } which is not something too elegant/robust. – raisercostin Jul 30 '15 at 06:40
  • Absolutely not! You may just send `{"$type": "Person", "name": "name1, "age": 1}` or `{"$type": "Person", "age": 1}` if name is not present. – Denis Mikhaylov Jul 30 '15 at 07:04
  • Can you share the imports that you are using to parse that string? I used `import scala.pickling.Defaults._, scala.pickling.json._` and it fails with `scala> val p2 = JSONPickle("""{"$type": "Person", "name": "name1", "age": 1}""").unpickle[Person] scala.MatchError: name1 (of class java.lang.String)` – raisercostin Jul 30 '15 at 12:25
1

To my understanding, scala-pickling can not handle missing fields.

If we look at the output of how scala-pickle pickles Option:

Some(9).pickle
// JSONPickle({
//   "$type": "scala.Some[scala.Int]",
//   "x": 9
// })

case class TestA(x: Option[Int])
TestA(None).pickle
// JSONPickle({
//   "$type": "TestA",
//   "x": {
//     "$type": "scala.None.type"
//   }
// })

You could use a json library instead of a serialization library.

Given your json and case class with an optional name:

case class Person(name:Option[String], age:Int)
val json =  """{"age":2}"""

With json4s:

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

parse(json).extract[Person]
// Person = Person(None,2)

With argonaut :

import argonaut._, Argonaut._

implicit def PersonCodecJson = 
  casecodec2(Person.apply, Person.unapply)("name", "age")

json.decodeOption[Person]
// Option[Person] = Some(Person(None,2))
Community
  • 1
  • 1
Peter Neyens
  • 9,770
  • 27
  • 33