Play WS请求报错:无BodyWritable隐式值,参数构造问题求助
首先,咱们来拆解你遇到的核心问题:一是样例类的JSON序列化逻辑不符合Play Json规范,二是直接用Map传参导致Play找不到对应的BodyWritable,这两个问题共同引发了那个序列化报错。
问题1:自定义Writes的实现不规范
你当前写的InitVideoUploadParamsWrites和VideoMetadataParamsWrites只是定义了普通的writes方法,并不是Play Json要求的Writes[T]类型。Play的Json序列化机制没法识别这类自定义隐式对象,自然没法帮你把样例类转换成目标JSON结构。
问题2:Map传参引发BodyWritable缺失
调用post(Map(...))时,Play WS找不到如何把这个Map转换成请求体的隐式BodyWritable,这就是报错No implicits found for parameter evidence$2: BodyWritable[Map[String, Object]]的直接原因。
正确解决方案
我们需要修正样例类的序列化逻辑,让Play能正确将对象转换成你需要的JSON结构,然后直接传递对象给post方法即可。
步骤1:修正样例类与Writes实现
推荐用Play Json的自动生成宏来简化实现,既简洁又不易出错:
import play.api.libs.json._ // 对应metadata节点的样例类 case class VideoMetadata(name: String, description: String) object VideoMetadata { implicit val writes: Writes[VideoMetadata] = Json.writes[VideoMetadata] } case class VideoMetadataParams(metadata: VideoMetadata) object VideoMetadataParams { implicit val writes: Writes[VideoMetadataParams] = Json.writes[VideoMetadataParams] } case class InitVideoUploadParams(videoMetadataParams: VideoMetadataParams) object InitVideoUploadParams { implicit val writes: Writes[InitVideoUploadParams] = Json.writes[InitVideoUploadParams] } // 辅助方法:快速创建请求对象 def buildInitUploadParams(name: String, desc: String): InitVideoUploadParams = { InitVideoUploadParams(VideoMetadataParams(VideoMetadata(name, desc))) }
步骤2:重构WS请求代码
现在直接传递InitVideoUploadParams对象给post方法,Play会自动利用隐式的Writes把对象序列化为JSON,同时默认的BodyWritable[JsValue]会帮你处理请求体的转换:
val uploadParams = buildInitUploadParams(fileName, fileName) ws.url(savaUrl + configObj.get[String]("kaltura.init")) .post(uploadParams)
验证生成的JSON结构
上面的代码会生成你需要的目标JSON:
{ "initVideoUploadParams": { "videoMetadataParams": { "metadata": { "name": "你的文件名", "description": "你的文件名" } } } }
可选:手动实现Writes(如果需要定制)
如果你需要更灵活的序列化逻辑,也可以手动实现Writes接口,比如:
object InitVideoUploadParams { implicit val writes: Writes[InitVideoUploadParams] = new Writes[InitVideoUploadParams] { override def writes(params: InitVideoUploadParams): JsValue = { Json.obj( "videoMetadataParams" -> Json.toJson(params.videoMetadataParams) ) } } }
不过宏生成的方式更省心,优先推荐使用。
内容的提问来源于stack exchange,提问作者Manish Kumar

