ScalikeJdbc是否支持Enum解析?能否与ScalaJson共用Case Class?
Great question! Let's break this down clearly: yes, ScalikeJdbc does support Enum parsing (with a small amount of setup), and you absolutely can use the same case class for both ScalikeJdbc database reads and Play ScalaJson parsing. Here's how to make it work smoothly.
1. ScalikeJdbc's Enum Parsing Capabilities
ScalikeJdbc doesn't have automatic Enum mapping for every scenario, but it provides flexible tools to add this support via TypeBinder (for reading from ResultSets) and ParameterBinder (for writing to the database).
Option 1: Use ScalikeJdbc's Built-in EnumTypeBinder
If your database stores Enum values as strings that exactly match your Scala Enum's entry names, use the EnumTypeBinder from the scalikejdbc-enumeration module (ensure it's in your dependencies):
import scalikejdbc._ import scalikejdbc.enumeration._ // Define your Scala Enum sealed trait UserStatus extends EnumEntry object UserStatus extends Enum[UserStatus] { case object Active extends UserStatus case object Inactive extends UserStatus case object Pending extends UserStatus override def values: Seq[UserStatus] = findValues } // Register the implicit TypeBinder for your Enum implicit val userStatusBinder: TypeBinder[UserStatus] = EnumTypeBinder.byName[UserStatus]
Option 2: Custom TypeBinder for Non-Matching Values
If your database uses numbers or different strings for Enums, create a custom TypeBinder to handle the mapping:
implicit val userStatusBinder: TypeBinder[UserStatus] = new TypeBinder[UserStatus] { // Map database value to Scala Enum override def apply(rs: java.sql.ResultSet, label: String): UserStatus = { val dbValue = rs.getString(label) dbValue match { case "ACT" => UserStatus.Active case "INA" => UserStatus.Inactive case "PEN" => UserStatus.Pending case _ => throw new IllegalArgumentException(s"Unknown status: $dbValue") } } override def apply(rs: java.sql.ResultSet, index: Int): UserStatus = { val dbValue = rs.getString(index) // Same matching logic as above dbValue match { case "ACT" => UserStatus.Active case "INA" => UserStatus.Inactive case "PEN" => UserStatus.Pending case _ => throw new IllegalArgumentException(s"Unknown status: $dbValue") } } }
For writing to the database, add a ParameterBinder to convert your Enum back to the database's expected format:
implicit val userStatusParameterBinder: ParameterBinder[UserStatus] = ParameterBinder { (status, stmt, idx) => val dbValue = status match { case UserStatus.Active => "ACT" case UserStatus.Inactive => "INA" case UserStatus.Pending => "PEN" } stmt.setString(idx, dbValue) }
2. Sharing the Same Case Class with Play ScalaJson
Your case class doesn't need any modifications to work with both tools—all parsing logic lives in implicit type classes (ScalikeJdbc's TypeBinder and Play Json's Format) that resolve at compile time.
Step 1: Define Your Case Class
Keep it focused on your data model:
case class User( id: Long, name: Option[String], // Handles optional/nullable fields status: UserStatus )
Step 2: Add Play Json Format for the Enum
Create an implicit Format to enable Play Json parsing for your Enum:
import play.api.libs.json._ implicit val userStatusFormat: Format[UserStatus] = new Format[UserStatus] { override def reads(json: JsValue): JsResult[UserStatus] = json match { case JsString(value) => UserStatus.values.find(_.entryName == value) .map(JsSuccess(_)) .getOrElse(JsError(s"Invalid status: $value")) case _ => JsError("Expected string value for status") } override def writes(status: UserStatus): JsValue = JsString(status.entryName) } // Play Json automatically handles Option fields, no extra setup needed for `name`
Step 3: Use the Case Class with Both Tools
Now you can use the same User case class for database reads and JSON parsing seamlessly:
ScalikeJdbc Query Example
val userId: Long = 123 val user: Option[User] = sql""" SELECT id, name, status FROM users WHERE id = $userId """.map(rs => User( rs.long("id"), rs.stringOpt("name"), // Handles nullable DB fields rs.get[UserStatus]("status") // Uses our implicit TypeBinder )).single().apply()
Play Json Parsing Example
val userJson = """{ "id": 123, "name": "Alice Smith", "status": "Active" }""" val parsedUser: User = Json.parse(userJson).as[User]
Key Takeaways
- ScalikeJdbc supports Enum parsing via built-in or custom
TypeBinderimplementations. - Play ScalaJson requires a custom
Formatfor Enums, but this is straightforward to implement. - You can use the exact same case class for both tools—all parsing logic is contained in implicit type classes, not the case class itself.
- Optional/nullable fields work naturally with both libraries (ScalikeJdbc uses
rs.stringOptetc., Play Json handlesOptionout of the box).
内容的提问来源于stack exchange,提问作者y2k-shubham

