Akka Remote迁移至Akka HTTP:无需大量开发实现JSON序列化
Hey there! I’ve been right where you are—moving away from Akka Remote’s auto-magical Protobuf serialization to JSON over HTTP, and dreading the thought of writing custom formatters for every complex case class in my app. Luckily, Scala has some fantastic libraries that handle this auto-magically, just like Akka Remote did for Protobuf. Here are the top options I’ve used successfully:
1. Circe (Most Hands-Off for Auto-Derivation)
Circe is my go-to for JSON serialization because its fully automatic derivation requires almost zero boilerplate—even for deeply nested case classes.
How to set it up:
- Add the Circe dependencies to your build (sbt example):
libraryDependencies ++= Seq( "io.circe" %% "circe-core" % "0.14.6", "io.circe" %% "circe-generic" % "0.14.6", "io.circe" %% "circe-parser" % "0.14.6" ) - For HTTP integration with Akka HTTP, add the marshaller dependency:
libraryDependencies += "de.heikoseeberger" %% "akka-http-circe" % "1.39.2"
Usage Example:
Suppose you have a complex nested case class:
case class Address(street: String, zipCode: String, city: String) case class User(id: Int, name: String, address: Address, preferences: Map[String, Boolean])
With Circe’s auto-derivation, you just import the right package, and serialization/deserialization works out of the box:
import io.circe.generic.auto._ import io.circe.syntax._ // Serialize to JSON val user = User(1, "Alice", Address("Main St", "12345", "New York"), Map("notifications" -> true)) val json = user.asJson.noSpaces // Deserialize from JSON import io.circe.parser.decode val decodedUser: Either[io.circe.Error, User] = decode[User](json)
For Akka HTTP routes, you can use the Circe marshallers to automatically handle JSON requests/responses:
import de.heikoseeberger.akkahttpcirce.FailFastCirceSupport._ val route = post { entity(as[User]) { user => complete(user.asJson) } }
2. Play JSON (Great if You’re Using Play Framework)
If your app is already using Play or you prefer its ecosystem, Play JSON’s macro-based formatters eliminate boilerplate for case classes.
Setup:
Add the Play JSON dependency (sbt):
libraryDependencies += "com.typesafe.play" %% "play-json" % "2.9.2"
For Akka HTTP integration, use the akka-http-play-json marshaller:
libraryDependencies += "de.heikoseeberger" %% "akka-http-play-json" % "1.39.2"
Usage Example:
For the same User and Address case classes, you just define implicit formats using the Json.format macro—no manual serialization code needed:
import play.api.libs.json._ implicit val addressFormat: OFormat[Address] = Json.format[Address] implicit val userFormat: OFormat[User] = Json.format[User] // Serialize val json = Json.toJson(user) val jsonString = Json.stringify(json) // Deserialize val decodedUser = Json.parse(jsonString).as[User]
The macro automatically generates the read/write logic for all fields, including nested case classes and collections like Map.
3. Spray JSON (Lightweight Option)
Spray JSON is a smaller, more lightweight library that also uses macros to generate formatters for case classes. It’s a good choice if you want minimal dependencies.
Setup:
Add the dependency (sbt):
libraryDependencies += "io.spray" %% "spray-json" % "1.3.6"
Usage Example:
You’ll need to extend DefaultJsonProtocol and use the jsonFormatN macros (where N is the number of fields in your case class):
import spray.json._ case class Address(street: String, zipCode: String, city: String) case class User(id: Int, name: String, address: Address, preferences: Map[String, Boolean]) object MyJsonProtocol extends DefaultJsonProtocol { implicit val addressFormat: RootJsonFormat[Address] = jsonFormat3(Address) implicit val userFormat: RootJsonFormat[User] = jsonFormat4(User) } // Use the protocol import MyJsonProtocol._ // Serialize val json = user.toJson.compactPrint // Deserialize val decodedUser = json.parseJson.convertTo[User]
While you have to explicitly call jsonFormatN for each case class, you still don’t write any manual serialization logic—all the heavy lifting is done by the macro.
Final Recommendation
If you want the least amount of boilerplate possible, go with Circe’s fully automatic derivation—it handles nested classes, collections, and even optional fields without you writing any extra code. If you’re already in the Play ecosystem, Play JSON is a seamless fit.
No matter which option you choose, you’ll avoid writing the tedious JSON formatters you were worried about, just like how Akka Remote handled Protobuf serialization automatically.
内容的提问来源于stack exchange,提问作者Jas

