jsonscalaparsingjson4s

Scala & json4s - parsing JSON with fields that start with a numeric character


I've got deeply nested JSON parsers (using json4s.jackson) that I'm trying to simplify using case classes.

My problem is... some of the fields start with numbers, but scala cannot have an arg name that starts with a numeric character.

Example:

import org.json4s.jackson.JsonMethods._
import org.json4s._

implicit val formats = DefaultFormats

val jsonStr = """{"5gLog":{"i":99}}"""      // <--- note the field "5gLog"
val jval = parse(jsonStr)

case class Raw5gLog(i: Int)
val raw5gLog = (jval \ "5gLog").extract[Raw5gLog]

This works. But what I need to do, because these fields are nested deep within the JSON... is something like this...

val jsonStr = """{"xgLog":{"i":99}}"""
val jval = parse(jsonStr)

case class RawRecord(xgLog: Raw5gLog)
val rawRecord = jval.extract[RawRecord]

This would work... if the fields were named like xgLog, but the fields are actually named like 5gLog as above, and I can't give an arg name to a class like 5gLog...

case class RawRecord(5gLog: Raw5gLog)
// error: Invalid literal number

I thought about something like

parse(jsonStr.replace("\"5g", "\"fiveg"))

But there's real data, beyond the field names, in the JSON that can be impacted.

The best solution I can figure is to add extra apply methods to the affected case classes...

case class RawRecord(fivegLog: Raw5gLog)

object RawRecord {
  def apply(jval: JValue): RawRecord =
    RawRecord( (jval \ "5gLog").extract[Raw5gLog] )
}

val rawRecord = RawRecord(jval)

But I feel like every time I make some structurally different workaround like this for an edge case, it's always the beginning of my code turning into a mess. I could give every case class a new apply method and use it for everything, but it seems like a lot of extra code for a small subset of the data.

Is there a better way?


Solution

  • Scala can use any string as a variable name, but you may have to quote it with backticks:

    case class RawRecord(`5gLog`: Raw5gLog)
    

    You also need to do this if you have a field called type or any other reserved word. This is how - can be a function name, for example.