title: spray-json and spray-routing: how to invoke JsonFormat write in complete
body: <p>I am trying to figure out how to get a custom JsonFormat write method to be invoked when using the routing directive complete. JsonFormat created with the jsonFormat set of helper functions work fine, but defining a complete JsonFormat will not get called.</p>
  
  <pre><code>sealed trait Error
  sealed trait ErrorWithReason extends Error {
    def reason: String
  }
  
  case class ValidationError(reason: String) extends ErrorWithReason
  case object EntityNotFound extends Error
  case class DatabaseError(reason: String) extends ErrorWithReason
  
  case class Record(a: String, b: String, error: Error)
  
  object MyJsonProtocol extends DefaultJsonProtocol {
    implicit object ErrorJsonFormat extends JsonFormat[Error] {
      def write(err: Error) = failure match {
        case e: ErrorWithReason =&gt; JsString(e.reason)
        case x =&gt; JsString(x.toString())
      }
      def read(value: JsValue) = {
        value match {
          //Really only intended to serialize to JSON for API responses, not implementing read
          case _ =&gt; throw new DeserializationException("Can't reliably deserialize Error")
        }
      }
    }
  
    implicit val record2Json = jsonFormat3(Record)
  }
  </code></pre>
  
  <p>And then a route like:</p>
  
  <pre><code>import MyJsonProtocol._
  
  trait TestRoute extends HttpService with Json4sSupport {
    path("testRoute") {
      val response: Record = getErrorRecord()
      complete(response)
    }
  }
  </code></pre>
  
  <p>If I add logging, I can see that the ErrorJsonFormat.write method never gets called.</p>
  
  <p>The ramifications are as follows showing what output I'm trying to get and what I actually get. Let's say the Record instance was Record("something", "somethingelse", EntityNotFound)</p>
  
  <p><strong>actual</strong></p>
  
  <pre><code>{
    "a": "something",
    "b": "somethingelse",
    "error": {}
  }
  </code></pre>
  
  <p><strong>intended</strong></p>
  
  <pre><code>{
    "a": "something",
    "b": "somethingelse",
    "error": "EntityNotFound"
  }
  </code></pre>
  
  <p>I was expecting that the <code>complete(record)</code> uses the implicit JsonFormat for Record which in turn relies on the implicit object ErrorJsonFormat that specifies the write method that creates the appropriate JsString field. Instead it seems to both recognize the provided ErrorJsonFormat while ignoring its instructions for serializing.</p>
  
  <p>I feel like there should be a solution that does not involve needing to replace <code>implicit val record2Json = jsonFormat3(Record)</code> with an explicit <code>implicit object RecordJsonFormat extends JsonFormat[Record] { ... }</code> </p>
  
  <p>So to summarize what I am asking</p>
  
  <ul>
  <li>Why does the serialization of Record fail to call the ErrorJsonFormat write method (what does it even do instead?) <strong>answered below</strong></li>
  <li>Is there a way to match my expectation while still using <code>complete(record)</code>?</li>
  </ul>
  
  <p><strong>Edit</strong></p>
  
  <p>Digging through the spray-json source code, there is an sbt-boilerplate template that seems to define the jsonFormat series of methods: <a href="https://github.com/spray/spray-json/blob/master/src/main/boilerplate/spray/json/ProductFormatsInstances.scala.template" rel="nofollow">https://github.com/spray/spray-json/blob/master/src/main/boilerplate/spray/json/ProductFormatsInstances.scala.template</a></p>
  
  <p>and the relevant product for jsonFormat3 from that seems to be :</p>
  
  <pre><code>def jsonFormat3[P1 :JF, P2 :JF, P3 :JF, T &lt;: Product :ClassManifest](construct: (P1, P2, P3) =&gt; T): RootJsonFormat[T] = {
    val Array(p1,p2,p3) = extractFieldNames(classManifest[T])
    jsonFormat(construct, p1, p2, p3)
  }
  
  def jsonFormat[P1 :JF, P2 :JF, P3 :JF, T &lt;: Product](construct: (P1, P2, P3) =&gt; T, fieldName1: String, fieldName2: String, fieldName3: String): RootJsonFormat[T] = new RootJsonFormat[T]{
    def write(p: T) = {
      val fields = new collection.mutable.ListBuffer[(String, JsValue)]
      fields.sizeHint(3 * 4)
  
      fields ++= productElement2Field[P1](fieldName1, p, 0)
      fields ++= productElement2Field[P2](fieldName2, p, 0)
      fields ++= productElement2Field[P3](fieldName3, p, 0)
  
      JsObject(fields: _*)
    }
    def read(value: JsValue) = {
      val p1V = fromField[P1](value, fieldName1)
      val p2V = fromField[P2](value, fieldName2)
      val p3V = fromField[P3](value, fieldName3)
  
      construct(p1v, p2v, p3v)
    }
  }
  </code></pre>
  
  <p>From this it would seem that jsonFormat3 itself is perfectly fine (if you trace into the productElement2Field it grabs the writer and directly calls write). The problem must then be that the <code>complete(record)</code> doesn't involve JsonFormat at all and somehow alternately marshals the object.</p>
  
  <p>So this seems to answer part 1: <strong><em>Why does the serialization of Record fail to call the ErrorJsonFormat write method (what does it even do instead?)</em></strong>. No JsonFormat is called because complete marshals via some other means.</p>
  
  <p>It seems the remaining question is if it is possible to provide a marshaller for the complete directive that will use the JsonFormat if it exists otherwise default to its normal behavior. I realize that I can generally rely on the default marshaller for basic case class serialization. But when I get a complicated trait/case class setup like in this example I need to use JsonFormat to get the proper response. Ideally, this distinction shouldn't have to be explicit for someone writing routes to need to know the situations where its the default marshaller as opposed to needing to invoke JsonFormat. Or in other words, needing to distinguish if the given type needs to be written as <code>complete(someType)</code> or <code>complete(someType.toJson)</code> feels wrong.</p>