Search code examples
jsonscalaspray

Spray JSON can't serialise case class


I am attempting to convert the following case class to/from JSON using Spray:

case class Interval(lower: Int, upper: Int)

This is achieved via:

implicit val intervalFormat = jsonFormat2(Interval)

This compiles, but gives the runtime error:

Cannot automatically determine case class field names and order for 'Interval', please use the 'jsonFormat' overload with explicit field name specification

A search on this error suggests that it typically arises when subclasses declare additional fields, which is not the case here.

Am I mistaken in thinking that Spray should be able to automatically format the interval class?

If so, then (as the error message appears to suggest) should I be providing a formatter with more explicit information about the fields of Interval? How might this most readily be achieved?

EDIT: The answer by @retrospectacus offers some helpful points, but none of them solve the problem. The workaround I adopted was to provide an explicit description of the types and names of the fields:

implicit val intervalFormat = jsonFormat[Int, Int,Interval](Interval, "lower", "upper")

This works, but I'm leaving the question open, since it's still not clear why this is necessary.


Solution

  • Common reasons for this error:

    • If you have a case object Interval (companion) somewhere, then the jsonFormat should be created like jsonFormat2(Interval.apply).
    • Adding a type annotation to the format can help: implicit val intervalFormat: RootJsonFormat[Interval] = ...
    • Your Interval class could be confused with another Interval class, possibly org.joda.time.Interval, either in the jsonFormat creation or in the place of case class creation or serialization - you may add a prefix or fix imports to avoid this.

    Hope this helps.

    EDIT: Another reason for this issue which I just encountered, is if you have any val declared within the case class, the serializer won't be able to automatically generate a format. E.g.

    case class Interval(from: Int, to: Int) {
      val size: Int = to - from
    }
    

    The error will be "java.lang.RuntimeException: Case class Interval declares additional fields".

    This can be solved using the jsonFormat overload as described above, or the val can be simply changed to a def.