5

I'm trying to make a simple example of a class serialization in Scala using json4s library, but even after extensively searching for it on the internet, unfortunately I couldn't find any satisfatory sample that would solve my problem.

Basically I have a simple class called Person and I want to extract an instance of this class from a JSON string.

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

So when I do this:

val jsonStr = "{\"name\":\"Socrates\", \"age\": 70}"
println(Serialization.read[Person](jsonStr))

I get this output:

"Person(Socrates,70,None)" // works fine!

But when I have no age parameter in JSON string, I get this error:

Exception in thread "main" org.json4s.package$MappingException: No usable value for age

I know that Person class has two required parameters in its constructor, but I would like to know if there's a way to make this conversion through a parser or something similar.

Also, I've tried to make this parser, but no success.

Thanks in advance for any help.

8
  • 1
    What do you want to receive as a result of parsing the JSON when there is no "age" parameter? Commented May 23, 2015 at 1:31
  • Obviously you need to use Option[Int] type for age or create your custom serializer: github.com/json4s/json4s#serializing-non-supported-types Commented May 23, 2015 at 3:17
  • @dan-getz, I will receive those JSON strings from a third party application, so I cannot guarantee that all parameters will be present on their requests, so I'm just trying to figure it out the options I have to make my parser robust (I started studying Scala language just a week ago). Commented May 23, 2015 at 17:03
  • @sap1ens, as I said, I've tried to make this parser using this exact sample, but no success. Thanks anyway. Commented May 23, 2015 at 17:05
  • 1
    "What are my options?" You could leave the existing exception as is, throw a different exception, return an Option, return a special value, use Option for the age parameter, use a special age number to represent "not specified", return a Try or Either... the list goes on and on. Are you asking for help coding a parser, or deciding what your code should do in the first place? Commented May 23, 2015 at 17:56

1 Answer 1

2

Assuming you do not want to make age optional by setting its type to Option, then you could write a custom serializer by extending CustomSerializer[Person]. The custom serializer takes a function from Formats to a tuple of PartialFunction[JValue, Person] (your Person deserializer) and PartialFunction[Any, JValue] (your serializer).

Assuming Person.DefaultAge is the default value you want to set for age if the age is not given, then the custom serializer could look as follows:

object PersonSerializer extends CustomSerializer[Person](formats => ( {
  case JObject(JField("name", JString(name)) :: JField("age", JInt(age)) :: Nil) => Person(name, age.toInt, None)
  case JObject(JField("name", JString(name)) :: JField("age", JInt(age)) :: JField("children", JArray(children)) :: Nil) => Person(name, age.toInt, Some(children map (child => formats.customDeserializer(formats).apply(TypeInfo(classOf[Person], None), child).asInstanceOf[Person])))
  case JObject(JField("name", JString(name)) :: Nil) => Person(name, Person.DefaultAge, None)
  case JObject(JField("name", JString(name)) :: JField("children", JArray(children)) :: Nil) => Person(name, Person.DefaultAge, Some(children map (child => formats.customDeserializer(formats).apply(TypeInfo(classOf[Person], None), child).asInstanceOf[Person])))
}, {
  case Person(name, age, None) => JObject(JField("name", JString(name)) :: JField("age", JInt(age)) :: Nil)
  case Person(name, age, Some(children)) => JObject(JField("name", JString(name)) :: JField("age", JInt(age)) :: JField("children", formats.customSerializer(formats).apply(children)) :: Nil)
}))

This could probably be simplified as there is a lot of repetition. Also, there might be a better way to recursively call serialization/deserialization.

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

1 Comment

Thank you very much, @KuluLimpa! It worked softly as I expected.

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.