xstack2000
xstack2000

Reputation: 139

Scala conditional None value assignment

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);

  }
}

Upvotes: 0

Views: 2165

Answers (2)

pagoda_5b
pagoda_5b

Reputation: 7383

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

Upvotes: 1

prayagupadhyay
prayagupadhyay

Reputation: 31262

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 
 }
}

Upvotes: 1

Related Questions