Marshalling in Spray.io
Marshalling in spray.io
Issue
When generating output from a Data type Spray looks for implicit Marshaller or UnMarshallers in the scope of the route in question.
There are some default marshallers for most of the common value types such as Int Long String and the Collections, as well as automatic marshallers for case classes
However these may or may not be available, because:-
- Your type has not been added to the Marshaller typeclass
- Your type is a case class but some of it’s fields have no marshallern
- You invoke a Future using the ask pattern and there is no execution context in scope.
Example
- consider this route from the Spray route Example project
- the route that get’s the Stats is the problem
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
|
- the code calls the listener actor, the one that sends the Bound message, and passes it the
Http.GetStats
message. - that actor responds with a Stats object.
- to prevent blocking the code uses the ask pattern to get a Future[Stats] object, ask returns a Future[Any] so it is cast to Future[Stats]
complete looks for a way to marshall Stats to a HttpEntity but runs into trouble….
- lets break it down
Execution Context
- if you kick of a Future, eg with the ask pattern for the Stats, you must include the following
- This uses the default execution context of the actor system and makes it implicitly available
1 2 |
|
- failure to do so will rsult in an error like, note we are trying to create a
Marshaller[Future[Stats]]
1 2 |
|
- Can’t marshall
- the marshalling system for Spray needs an implicit marshaller for Stats
- Stats doesn not have one in it’s companion object
- in fact it doesn’t have a companion object it is a case class
- note the error is identical to the previous which is annoying!
1 2 |
|
- so we need to bring one into scope, something like this will do although we could use Marshaller.of[Stats] function too with a bit more boilerplate.
1 2 3 4 5 6 7 8 9 10 11 12 |
|
JSON
So with the points above the code will work and on hittingthe /Stats
URL will render the stats as a String
But what about JSON?
Spray supports JSON an even automatically supports case classes made up from standard value fields all you have to do is
1
|
|
- ie mix that into your route or just import the Object’s vals
- and it will bring an implicit RootJsonFormat[T] into scope which is a Marshaller
- and job done right?
Stats has a FiniteDuration
- look at
Stats
- is not made of the default value types it has a FiniteDuration
1 2 3 4 5 6 7 8 |
|
- there is no default RootJsonFormat for that
so we need some help
Create an implicit RootJsonFormat[FiniteDuration]
1
|
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
the end.