0

I am trying to convert com.google.gson.JsonObject to case class object. Sometime some element in the record are missing in which case I want it to be assigned as None to case class member

object tmp {
  case class person(name: String, age: Long)
  def main(args: Array[String]): Unit = {
   val parser = new JsonParser();

   //PERSON 2
   val record2 = parser.parse("""{"name":"xyz"}""").getAsJsonObject()

   val record2_name = record2.get("name").getAsString.toLowerCase
   val record2_age = if(record2.get("age") != null) record2.get("age") else None

   val person2 = new person(record2_name,record2_age)  //-> Type Mismatch, expected: Long, actual: Long

   println(person2);

  }
}

2 Answers 2

1

In your case record2_age is of type JsonElement which is simply of type java Object, but since you are assigning None to it, it becomes Any WHICH you are trying to assign to type Long.

Short answer would be ,

val person = new person(jsonObject.get("name").getAsString.toLowerCase,
    Option(jsonObject.get("age")).map(_.getAsLong).getOrElse(0l))

This way if jsonObject.get("age") is null, Option(null) gives you None, or if present you get Option(28) = Some(28)

You probably want your age to be 0l if empty. If you want it to be None, then you can use Option[Long].

1) simpler way

class GsonCaseClassSpecs extends FunSpec {

  describe("case class conversion") {

    it("converts gson with name/age to case class") {

      case class person(name: String, age: Long)

      val parser = new JsonParser()

      //case 1
      val jsonObject : JsonObject = parser.parse("""{"name":"xyz"}""").getAsJsonObject

      val age = jsonObject.get("age") match {
        case null => None
        case value => Some(value.getAsLong)
      }

      val person1 = new person(jsonObject.get("name").getAsString.toLowerCase, age.getOrElse(0l))

      assert(person1.name == "xyz")
      assert(person1.age == 0)

      //case 2
      val jsonObject2 : JsonObject = parser.parse("""{"name":"xyz", "age" : 28}""").getAsJsonObject

      val age2 : Option[Long] = jsonObject2.get("age") match {
        case null => None
        case value => Some(value.getAsLong)
      }

      val person2 = new person(jsonObject2.get("name").getAsString.toLowerCase, age2.getOrElse(0l))

      assert(person2.name == "xyz")
      assert(person2.age == 28)
    }

  }
}

2) If you want to make the age to be Option[Long]. Option[T] can have Some(x) or None.

class CaseClassFunSpecs extends FunSpec {

 it("converts json to case class with empty age"){

  case class person(name: String, age: Option[Long])

  val parser = new JsonParser()

  val json = parser.parse("""{"name":"xyz"}""").getAsJsonObject()

  val personInstance = new person(json.get("name").getAsString.toLowerCase,
    Option(json.get("age")).map(_.getAsLong))

  assert(personInstance.name == "xyz")
  assert(personInstance.age == None)
  // NOTE
  // do not do personInstance.age.get which would throw
  // None.get
  // java.util.NoSuchElementException: None.get
  // at scala.None$.get(Option.scala:347)
  // at scala.None$.get(Option.scala:345)

  //rather use pattern match
  personInstance.age match {
    case Some(x) => println("value = " + x)
    case None => throw new RuntimeException("Age can not be empty.")
  }
  }

 it("converts json to case class with non-empty age"){

  case class person(name: String, age: Option[Long])

  val parser = new JsonParser()

  val json = parser.parse("""{"name":"xyz", "age" : 28}""").getAsJsonObject()

  val personInstance = new person(json.get("name").getAsString.toLowerCase,
    Option(json.get("age")).map(_.getAsLong))

  assert(personInstance.name == "xyz")
  assert(personInstance.age == Some(28))
  assert(personInstance.age.get == 28) //.get gives you the value 
 }
}
Sign up to request clarification or add additional context in comments.

3 Comments

This is setting age as 0 which could be. I need something to indicate this element was missing from the row.
@xstack2000 If thats the case, then you need Option[Long]. See the updated answer. Let me know if that helps
@xstack2000 also read NOTE while using ageOption, as .get on None will throw exception, rather use pattern matching as described above.
1

You simply can't call a parameter of one type, age: Long in your case, with an argument of a different type Option[Long].

At least this is what your question seems to imply.

You need to define the attributes that could be missing as Options.

e.g. in your example

case class person(name: String, age: Option[Long])

and then when you extract the json value you can make use of the Option.apply method, that returns None if the argument is null

…
val record2_age = Option(record2.get("age")).map(_.getAsLong) // None if get("age) returns null
…
val person2 = new person(record2_name,record2_age)  //There should be no more type mismatch now

2 Comments

I did try Option but it still doesnt work val person2 = new person(record2_name, record2_age) //-> Type Mismatch, expected: Option[Long], actual: Option[jsonElement]
Updated the answer as in @prayagupd's answer, try now

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.