2

I am parsing a json response from a web service which has some fields defined using hyphens. I want to convert these names to mixed case names in my scala case class. I thought to use the camelizeKeys stipulation but it doesn't seem to work. So for example say I have a json response like:

{"offset":0,"total":359,"per-page":20}

to be converted to:

case class Response(offset: Int, total: Int, perPage: Int)

and I do:

parse(str).camelizeKeys.extract[Response]

I get the error:

Ex: org.json4s.package$MappingException: No usable value for perPage Did not find value which can be converted into int

Shadowlands
  • 14,994
  • 4
  • 45
  • 43
user79074
  • 4,937
  • 5
  • 29
  • 57
  • 1
    `.camelizeKeys` works on field names containing underscores, not hyphens. You could transform the field name(s) specifically (see, for example, [here](https://github.com/json4s/json4s) - search the page for "camelizeKeys"), or try to do a general string `.replace('-','_')` (on field names only, ideally). – Shadowlands Sep 24 '15 at 00:07
  • Yes I had thought of that but was wondering if there was a more specific solution. You can't just replace all hyphens as this can cause problems with the data (date representations for example). See the solution below. – user79074 Sep 24 '15 at 08:01
  • if you can use `json4s-jackson` instead of native json4s parser, maybe you can write something like `case class Response(..., @JsonProperty("per-page") perPage: Int)` http://stackoverflow.com/questions/25654811/jsonignore-serialising-scala-case-class-property-using-jackon-and-json4s – ymonad Sep 24 '15 at 08:19

2 Answers2

0

A work around is to replace all occurrences of the hyphen with an underscore before parsing the text. So one could do the following:

parse(str.replaceAll("([a-z])-([a-z])", "$1_$2")).camelizeKeys.extract[Response] 

But this solution is limited as with complicated data structures it may not work; you could end up corrupting the data returned if any field values contains such a pattern. So a more complete solution was to write my own replaceAll function:

def replaceAll(str: String, regex: String)(f: String => String) = {
    val pattern = regex.r
    val (s, i) = (("", 0) /: pattern.findAllMatchIn(str)) { case ((s, i), m) =>
        (s + str.substring(i, m.start) + f(m.toString), m.end)
    }
    s + str.substring(i)
}

and apply it to my json string thus:

replaceAll(str, "\"[0-9a-z\\-]*\":")(_.replace('-', '_'))
user79074
  • 4,937
  • 5
  • 29
  • 57
0

You can replace the hyphens by underscores as below.

def replaceHyphens(value: JValue): JValue = {
    value.transformField {
        case JField(name, x) => JField(name.replaceAll("-", "_"), x)
    }
}

This function is implemented by referring to rewriteJsonAST in json4s

replaceHyphens(parse(str)).camelizeKeys.extract[Response]
RainVision
  • 81
  • 1
  • 4