You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Akka Remote迁移至Akka HTTP:无需大量开发实现JSON序列化

Solutions for Auto-Serializing Scala Case Classes to JSON for HTTP (No Boilerplate!)

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:35:16