Escrever um Valor Arbitrário Não foi Encontrado em um Caso de Classe Usando o Play (2.2) Scala JSON Ferramenta
-
21-12-2019 - |
Pergunta
Gostaria de implementar um Writes
que emite um objeto JSON que não se encontra na classe que está sendo serializado.
Para o caso da classe:
case class Foo(i:Int, s:String)
Eu estou olhando para produzir:
{
"i": <int>,
"s": "<string>",
"other": "Some value."
}
A ingênua primeira tentativa foi:
val writes: Writes[Foo] = ((
(__ \ "i").write[Int] and
(__ \ "s").write[String] and
(__ \ "other").write("Some value.")
)(unlift(Foo.unapply))
Naturalmente, que não vai compilar como o subsequente and
chamadas de produzir um CanBuild3
e Foo
's unapply
produz um Tuple2
.Eu olhei para anexar um valor para o resultado, a produção de um Tuple3
, mas o que eu encontrei parece muito ruim e o idioma mantenedores não implementá-lo.
Existem maneiras de contornar isso, mas eu prefiro não profanar o meu modelo de classes com estes decorador de valores que eu gostaria de incluir o resultante JSON.
Alguma sugestão?
É digno de nota que você pode vá para a outra direção, fornecendo valores com Reads.pure
para os casos onde não existir um valor em JSON, mas é especificado pelo objeto resultante.
Solução
Você pode fazer isso muito claramente por desugaring um pouco:
val writes: Writes[Foo] = (
(__ \ "i").write[Int] and
(__ \ "s").write[String] and
(__ \ "other").write[String]
)(foo => (foo.i, foo.s, "Some value."))
O unlift(Foo.unapply)
é apenas uma maneira elegante para obter uma função a partir de uma Foo
para que uma tupla do tipo exigido pelo anterior aplicativo construtor de expressão, e você pode substituí-lo com a sua própria função que pode adicionar o que você quiser.
Se você realmente queria mesmo aspirador de sintaxe, você pode usar Disforme:
import shapeless.syntax.std.tuple._
val writes: Writes[Foo] = (
(__ \ "i").write[Int] and
(__ \ "s").write[String] and
(__ \ "other").write[String]
)(_ :+ "Some value.")
É bonita, mas pode ser um exagero.
Outras dicas
Outra opção é usar um construtor objeto que implementa um unapply
que retorna a valores extra.Isto torna as Gravações de limpeza, mas adiciona um novo objeto.Eu encontrei este úteis, apesar de como aplicar e unapply método pode ser usado para extra massageando de dados para o objeto final (ex.: https://stackoverflow.com/a/22504468/1085606)
Exemplo:
case class Foo(i: Int, s: String)
object FooBuilder {
def unapply(foo: Foo): Option[(Int, String, String)] = {
Some((foo.i, foo.s, "Some extra value"))
}
}
val writes: Writes[Foo] = ((
(__ \ "i").write[Int] and
(__ \ "s").write[String] and
(__ \ "other").write[String]
)(unlift(FooBuilder.unapply))