As a beginner to both scala and akka-http, I am trying to hook into the serialization aka marshalling process.
The project uses [email protected] and [email protected]". Furthermore, it has the akka-http-spray-json
dependency included.
In the codebase, we use Java.Util.Currency
(It may be deprecated which is not important as I'd still like to know how to add a custom marshaller.)
Given this example controller:
def getCurrencyExample: Route = {
path("currencyExample") {
val currency: Currency = Currency.getInstance("EUR")
val code: String = currency.getCurrencyCode
val shouldBeFormated = collection.immutable.HashMap(
"currencyCode" -> code,
"currencyObject" -> currency
)
complete(shouldBeFormated)
}
}
I get a response like this where the currency object becomes empty:
{
currencyObject: { },
currencyCode: "EUR",
}
I expect something like:
{
currencyObject: "EUR",
currencyCode: "EUR",
}
The currency
object should be transformed into a JSON string. And since I do not want to transform each response manually, I want to hook into marshalling process and have it done in the background.
I want to add a custom marhaller only for Java.Util.Currency
objects, yet even reading up on the docs I am very unsure how to proceed.
There are multiple approaches described, and I am not sure which fits my need, or where to start.
I tried creating my own CurrencyJsonProtocol
:
package com.foo.api.marshallers
import java.util.Currency
import spray.json.{DefaultJsonProtocol, JsString, JsValue, RootJsonFormat}
object CurrencyJsonProtocol extends DefaultJsonProtocol {
implicit object CurrencyJsonFormat extends RootJsonFormat[Currency] {
override def read(json: JsValue): Currency = {
Currency.getInstance(json.toString)
}
override def write(obj: Currency): JsValue = {
JsString(obj.getCurrencyCode)
}
}
}
yet the mere existence of the file breaks my project:
[error] RouteDefinitons.scala:90:16: type mismatch;
[error] found : scala.collection.immutable.HashMap[String,java.io.Serializable]
[error] required: akka.http.scaladsl.marshalling.ToResponseMarshallable
[error] complete(shouldBeFormated)
[error] ^
[error] one error found
[error] (Compile / compileIncremental) Compilation failed
and I have no idea why. (It was crashing due to my package name being called marshaller
. That completely broke the compilation of the project.
case class
in my answer, that would allow you not to loose the needed type information, at the expense of one moreJsonFormat
to write. – Laroche{}
. From my current understanding it appears as if I have to create a marshaller for each case class which seems redundant and verbose. – LetteJsonFormat
for each case class, yes. But still, you only need to writeJsonFormat
once for members likeCurrency
, they will be found through implicit resolution. Writing eachJsonFormat
separately is considered normal as those represent the public interface of your module/application. – LarocheCurrency
gets formatted as{}
do you already have aJsonFormat
for that? – LarocheJsonFormat
for that. Why do I want/need it? The entire marshalling process still feels like black magic to me and I don't understand the reasoning behind it and how to set it up. – Lette