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.
Marshalling is like serialization, except marshalling also records codebases. Marshalling is different from serialization in that marshalling treats remote objects specially. Any object whose methods can be invoked [on an object in another Java virtual machine] must implement the java.
“Unmarshalling” is the process of converting some kind of a lower-level representation, often a “wire format”, into a higher-level (object) structure. Other popular names for it are “Deserialization” or “Unpickling”.
Marshalling is the process of converting a higher-level (object) structure into some kind of lower-level representation, often a “wire format”. Other popular names for marshalling are “serialization” or “pickling”.
From what I understand, you have all the pieces, you just need to put them together.
Spray json provides support for marshalling common types, such as Int, String, Boolean, List, Map, etc. But it doesn't know how to marshall 'Currency'. And to solve that you have created a custom marshaller for 'Currency' objects. You just need to plug it in the right place. All that you have to do is import the marshaller from your CurrencyJsonProtocol
into your Controller like below:
import CurrencyJsonProtocol._
Also make sure you have the below imports as well:
import spray.httpx.SprayJsonSupport._
import spray.json.DefaultJsonProtocol._
And spray-json should automatically pick that up.
To understand how it works, you need to understand about implicits in scala. Although it looks like magic when you come from java-world like me, I can assure you it's not.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With