需要帮助处理 reactivemongo 中的 IllegalArgumentException
Need help handling IllegalArgumentException in reactivemongo
下面的代码尝试使用 Reactivemongo 按 ID 获取文档。但是不知道如何处理ID错误时抛出的IllegalArgumentException!
尝试了下面的代码,但编译器对 case _ => Future.successful(None)
不满意,它说:found scala.concurrent.Future[None.type] required Option[SomeModel]
。也试过 case _ => None
但没有成功。
def getById(id: String)(implicit ec: ExecutionContext): Future[Option[SomeModel]]={
this.get( BSONDocument("_id" -> BSONObjectID(id)) ).map {
res => Future.successful(res)
}.recover {
case _ => Future.successful(None)
}
}
def get(query: BSONDocument)(implicit ec: ExecutionContext): Future[Option[SomeModel]]= {
collection.find(query).one[SomeModel](ReadPreference.Primary)
}
你在混淆 recover
and recoverWith
。
两个函数都需要 PartialFunction
接受 Throwable
并且两个函数 return 都接受 Future[U]
,但是
recover
的PartialFunction
应该return一个U
- 而
recoverWith
应该 return 一个 Future[U]
.
在你的情况下,你可以使用 recover
:
get(BSONDocument("_id" -> BSONObjectID(id)))
.recover { case _ => None }
// you don't need map(res => Future.successful(res)
更新:您可以将 get
编辑为 return 失败的 Future
而不是抛出 IllegalArgumentException
。一种可能的方法是使用 Try
及其 recover
:
import scala.util.Try
def get(query: BSONDocument)(implicit ec: ExecutionContext): Future[Option[SomeModel]] =
Try(collection.find(query).one[SomeModel](ReadPreference.Primary))
.recover{ case t => Future.failed(t) }.get
更新:
我做的时候它起作用了
def getById(id: String)(implicit ec: ExecutionContext): Future[Option[SomeModel]]={
Try(this.get(BSONDocument("_id" -> BSONObjectID(id)))).recover{ case t => Future.failed(t) }.get
}
def get(query: BSONDocument)(implicit ec: ExecutionContext): Future[Option[SomeModel]]={
collection.find(query).one[SomeModel](ReadPreference.Primary)
}
据我了解你的问题,
...I don't know how to deal with the IllegalArgumentException thrown when the ID is wrong!
我认为,更好的解决方案是
def getById(id: String)(implicit ec: ExecutionContext): Future[Option[SomeModel]]={
//Try to parse bson id from string. This method return Try[BSONObjectId] and we can simple `match` them
BSONObjectId.parse(id) match {
// valid bson id
case Success(bsonId) => this.get( BSONDocument("_id" -> bsonId) )
//We catch IllegalArgumentException and just return None
case Failure(ex) => Future[Option[SomeModel]](None)
}
}
在您的代码中,Scala 在调用 get
方法之前尝试从字符串中解析 BSONObjectId,如果字符串 id 无效,则 BSON 在当前线程中抛出异常(不在 Future
方法的结果中 get
).这就是 recover {case _ => Future.successful(None)}
不会执行的原因。方法 recover
和 recoverWith
仅在 Future
存储一些异常时执行。例如,此代码也可以工作:
def getById(id: String)(implicit ec: ExecutionContext): Future[Option[SomeModel]]={
//create Future, that will be store exception (if id is invalid) or valid BSON id.
//method flatMap because this.get return Future type.
Future(BSONObjectId(id)).flatMap{ bsonId =>
//this executes only if string id is valid bson.
this.get( BSONDocument("_id" -> bsonId) )
}.recover{
//this will be execute only if string id is invalid bson.
// the best practice to catch non-fatal Throwables via class scala.util.control.NonFatal
case NonFatal(e) => None
}
}
但是这个变体很复杂(再创建一个 Future
,flatMap
它们,用 NonFatal
控制恢复)。我更喜欢使用 parse
方法的第一个变体(没有一些额外的期货和控制,它更容易)。
下面的代码尝试使用 Reactivemongo 按 ID 获取文档。但是不知道如何处理ID错误时抛出的IllegalArgumentException!
尝试了下面的代码,但编译器对 case _ => Future.successful(None)
不满意,它说:found scala.concurrent.Future[None.type] required Option[SomeModel]
。也试过 case _ => None
但没有成功。
def getById(id: String)(implicit ec: ExecutionContext): Future[Option[SomeModel]]={
this.get( BSONDocument("_id" -> BSONObjectID(id)) ).map {
res => Future.successful(res)
}.recover {
case _ => Future.successful(None)
}
}
def get(query: BSONDocument)(implicit ec: ExecutionContext): Future[Option[SomeModel]]= {
collection.find(query).one[SomeModel](ReadPreference.Primary)
}
你在混淆 recover
and recoverWith
。
两个函数都需要 PartialFunction
接受 Throwable
并且两个函数 return 都接受 Future[U]
,但是
recover
的PartialFunction
应该return一个U
- 而
recoverWith
应该 return 一个Future[U]
.
在你的情况下,你可以使用 recover
:
get(BSONDocument("_id" -> BSONObjectID(id)))
.recover { case _ => None }
// you don't need map(res => Future.successful(res)
更新:您可以将 get
编辑为 return 失败的 Future
而不是抛出 IllegalArgumentException
。一种可能的方法是使用 Try
及其 recover
:
import scala.util.Try
def get(query: BSONDocument)(implicit ec: ExecutionContext): Future[Option[SomeModel]] =
Try(collection.find(query).one[SomeModel](ReadPreference.Primary))
.recover{ case t => Future.failed(t) }.get
更新:
我做的时候它起作用了
def getById(id: String)(implicit ec: ExecutionContext): Future[Option[SomeModel]]={
Try(this.get(BSONDocument("_id" -> BSONObjectID(id)))).recover{ case t => Future.failed(t) }.get
}
def get(query: BSONDocument)(implicit ec: ExecutionContext): Future[Option[SomeModel]]={
collection.find(query).one[SomeModel](ReadPreference.Primary)
}
据我了解你的问题,
...I don't know how to deal with the IllegalArgumentException thrown when the ID is wrong!
我认为,更好的解决方案是
def getById(id: String)(implicit ec: ExecutionContext): Future[Option[SomeModel]]={
//Try to parse bson id from string. This method return Try[BSONObjectId] and we can simple `match` them
BSONObjectId.parse(id) match {
// valid bson id
case Success(bsonId) => this.get( BSONDocument("_id" -> bsonId) )
//We catch IllegalArgumentException and just return None
case Failure(ex) => Future[Option[SomeModel]](None)
}
}
在您的代码中,Scala 在调用 get
方法之前尝试从字符串中解析 BSONObjectId,如果字符串 id 无效,则 BSON 在当前线程中抛出异常(不在 Future
方法的结果中 get
).这就是 recover {case _ => Future.successful(None)}
不会执行的原因。方法 recover
和 recoverWith
仅在 Future
存储一些异常时执行。例如,此代码也可以工作:
def getById(id: String)(implicit ec: ExecutionContext): Future[Option[SomeModel]]={
//create Future, that will be store exception (if id is invalid) or valid BSON id.
//method flatMap because this.get return Future type.
Future(BSONObjectId(id)).flatMap{ bsonId =>
//this executes only if string id is valid bson.
this.get( BSONDocument("_id" -> bsonId) )
}.recover{
//this will be execute only if string id is invalid bson.
// the best practice to catch non-fatal Throwables via class scala.util.control.NonFatal
case NonFatal(e) => None
}
}
但是这个变体很复杂(再创建一个 Future
,flatMap
它们,用 NonFatal
控制恢复)。我更喜欢使用 parse
方法的第一个变体(没有一些额外的期货和控制,它更容易)。