Outputting 'null' for Option[T] in play-json serialization when value is None

The Json.writes macro generates a writeNullable[T] for optional fields. Like you know (or not), writeNullable[T] omits the field if the value is None, whereas write[Option[T]] generates a null field.

Defining a custom writer is the only option you have to get this behavior.

( 
  (__ \ 'name).write[String] and
  (__ \ 'address).write[Option[String]]
)(unlift(Person.unapply _))

Not a real solution for you situation. But slightly better than having to manually write the writes

I created a helper class that can "ensure" fields.

implicit class WritesOps[A](val self: Writes[A]) extends AnyVal {
    def ensureField(fieldName: String, path: JsPath = __, value: JsValue = JsNull): Writes[A] = {
      val update = path.json.update(
        __.read[JsObject].map( o => if(o.keys.contains(fieldName)) o else o ++ Json.obj(fieldName -> value))
      )
      self.transform(js => js.validate(update) match {
        case JsSuccess(v,_) => v
        case err: JsError => throw new JsResultException(err.errors)
      })
    }

    def ensureFields(fieldNames: String*)(value: JsValue = JsNull, path: JsPath = __): Writes[A] =
      fieldNames.foldLeft(self)((w, fn) => w.ensureField(fn, path, value))

}

so that you can write

Json.writes[Person].ensureFields("address")()

You can use a custom implicit JsonConfiguration, see Customize the macro to output null

implicit val config = JsonConfiguration(optionHandlers = OptionHandlers.WritesNull)

implicit val personWrites = Json.writes[Person]    
Json.toJson(Person("John Smith", None))