Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handling same field with different value type #1214

Open
HelloJeevan opened this issue Oct 17, 2024 · 3 comments
Open

Handling same field with different value type #1214

HelloJeevan opened this issue Oct 17, 2024 · 3 comments
Labels

Comments

@HelloJeevan
Copy link

Hey,
Actually i am using jsoniter-scala lib but i am having situation like this

    val jsonString1 = """{"name": "foo", "id": "2604"}"""
    val jsonString2 = """{"name": "bar", "id": 2105}"""

Can we desrialize the json request in which we get same field sometime as integer and sometime as string with having same case class...i have tried using Either and AnyVal data type but not able to implement it

case class Person(name: String, id: Either[String, Int])

I am open to all method to handle this kind of situation
Thanks

@plokhotnyuk
Copy link
Owner

plokhotnyuk commented Oct 17, 2024

@HelloJeevan Thanks for the question!

If you just need to parse both numeric and stringified JSON values as Int then you should define the following custom codec before the make[Person] call:

implicit val customCodecOfInt: JsonValueCodec[Int] = new JsonValueCodec[Int] {
  def decodeValue(in: JsonReader, default: Int): Int =
    if (in.isNextToken('"')) {
      in.rollbackToken()
      in.readStringAsInt()
    } else {
      in.rollbackToken()
      in.readInt()
    }

  def encodeValue(x: Int, out: JsonWriter): Unit = out.writeVal(x)

  def nullValue: Int = 0
}

Also, please, see more advanced example of JavaScript compatible codec for Long here

@HelloJeevan
Copy link
Author

HelloJeevan commented Oct 17, 2024

Hey @plokhotnyuk thanks for replying really appriciate that
Can not we deserialize directly the JSON request through some readFromString method becuase we are already doing that in our code base so that it can in sync with the code we currently have.
Can you show me how we can deserilaize the JSON request i have provided that will provide more insight actually i am new to this library

@plokhotnyuk
Copy link
Owner

plokhotnyuk commented Oct 20, 2024

Here is a script that tests the proposed solution for you:

//> using dep "com.github.plokhotnyuk.jsoniter-scala::jsoniter-scala-core::2.31.0"
//> using compileOnly.dep "com.github.plokhotnyuk.jsoniter-scala::jsoniter-scala-macros::2.31.0"

import com.github.plokhotnyuk.jsoniter_scala.macros._
import com.github.plokhotnyuk.jsoniter_scala.core._

case class Person(name: String, id: Int)

implicit val customCodecOfInt: JsonValueCodec[Int] = new JsonValueCodec {
  def decodeValue(in: JsonReader, default: Int): Int =
    if (in.isNextToken('"')) {
      in.rollbackToken()
      in.readStringAsInt()
    } else {
      in.rollbackToken()
      in.readInt()
    }

  def encodeValue(x: Int, out: JsonWriter): Unit = out.writeVal(x)

  def nullValue: Int = 0
}

implicit val personCodec: JsonValueCodec[Person] = JsonCodecMaker.make

val person = try readFromStream[Person](System.in) catch {
  case ex: Throwable => ex.printStackTrace(System.err)
}

println(person)

It accepts JSON string from System.in and prints parsed Person to System.out.
Please store that code snippet in some file and use scala-cli to compile and run it for different input in Linux using the following commands:

scala-cli script.sc <<< '{"name": "foo", "id": "2604"}'
scala-cli script.sc <<< '{"name": "foo", "id": 2604}'

Expected output for both inputs is the same:

Person(foo,2604)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants