1

I need to parse the following json string:

{"type": 1}

The case class I am using looks like:

case class MyJsonObj(
    val type: Int
)

However, this confuses Scala since 'type' is a keyword. So, I tried using @JsonProperty annotation from Jacson/Jerkson as follows:

case class MyJsonObj(
    @JsonProperty("type") val myType: Int
)

However, the Json parser still refuses to look for 'type' string in json instead of 'myType'. Following sample code illustrates the problem:

import com.codahale.jerkson.Json._
import org.codehaus.jackson.annotate._

case class MyJsonObj(
    @JsonProperty("type") val myType: Int
)

object SimpleExample {
  def main(args: Array[String]) {
    val jsonLine = """{"type":1}"""
    val JsonObj = parse[MyJsonObj](jsonLine)
}

I get the following error:

[error] (run-main-a) com.codahale.jerkson.ParsingException: Invalid JSON. Needed [myType], but found [type].

P.S: As seen above, I am using jerkson/jackson, but wouldn't mind switching to some other json parsing library if that makes life easier.

gjain
  • 4,468
  • 5
  • 39
  • 47

3 Answers3

4

Use backquotes to prevent the Scala compiler from interpreting type as the keyword:

case class MyJsonObj(
    val `type`: Int
)
wingedsubmariner
  • 13,350
  • 1
  • 27
  • 52
  • Although that would work, I am really looking for the reason why @JsonProperty annotation didn't work as expected. Also, I want the val name to be more meaningful than just 'type'. – gjain Apr 17 '14 at 17:22
  • 1
    This may be an issue with Scala making all fields private and automatically generating getter and setter methods. You might be able to use Scala's [meta annotations](http://www.scala-lang.org/api/current/index.html#scala.annotation.meta.package). What happens if you replace `@JsonProperty("type")` with `@(JsonProperty("type") @field @getter @setter)`? – wingedsubmariner Apr 17 '14 at 18:20
3

I suspect you aren't enabling Scala support in Jackson properly.

I've tried this:

object Test extends App {

  val mapper = new ObjectMapper
  mapper.registerModule(DefaultScalaModule)
  println(mapper.writeValueAsString(MyJsonObj(1)))

  val obj = mapper.readValue("""{"type":1}""", classOf[MyJsonObj])
  println(obj.myType)
}

case class MyJsonObj(@JsonProperty("type") myType: Int)

And I get:

{"type":1}
1

Note that I've added Scala support to the object mapper by calling registerModule

sksamuel
  • 16,154
  • 8
  • 60
  • 108
3

As @wingedsubmariner implied, the answer lies with Scala meta annotations.

This worked for me:

import scala.annotation.meta.field

case class MyJsonObj(
    @(JsonProperty @field)("type") val myType: Int
)

This is in addition to mapper.registerModule(DefaultScalaModule), which you'll probably need if you're deserializing into a Scala class.

Larry B.
  • 753
  • 6
  • 21