2015-11-11 91 views
0

以下代码尝试使用Reactivemongo通过ID获取文档。但是,我不知道如何处理ID错误时抛出的IllegalArgumentException! 试过下面的代码,但编译器不满意case _ => Future.successful(None),它说:found scala.concurrent.Future[None.type] required Option[SomeModel]。也试过case _ => None没有成功。需要帮助处理reactivemongo中的IllegalArgumentException

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) 
    } 

回答

1

你很困惑recoverrecoverWith

两个功能期待PartialFunction其接受Throwable和两个函数返回一个Future[U],但

  • recoverPartialFunction应该返回一个U
  • recoverWith的应返回Future[U]

在你的情况,你可以使用recover

get(BSONDocument("_id" -> BSONObjectID(id))) 
    .recover { case _ => None } 
    // you don't need map(res => Future.successful(res) 

更新:您可以编辑get返回失败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) 
    } 
+0

谢谢,编译器现在感觉好多了。但我无法捕捉到这个例外。说'val resultFuture = get(BSONDocument(“_ id” - > BSONObjectID(id))) .recover {case _ => None}既不resultFuture.onFailure也不resultFuture.onSuccess被达到/匹配。我如何匹配recover'case _ => None'模式? – Mutaz

+0

'collection.find'是否抛出'IllegalArgumentException'或返回失败的'Future'? –

+0

仍然抛出'IllegalArgumentException' – Mutaz

1

...我不知道如何去处理ID错误时抛出的IllegalArgumentException异常!

我认为,更好的解决方案是

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) 
    } 
} 

在代码中,斯卡拉尝试之前调用get方法从字符串解析BSONObjectId,如果字符串ID无效BSON在当前线程抛出异常(未在方法getFuture结果中)。这就是为什么recover {case _ => Future.successful(None)}不会执行。方法recoverrecoverWith仅在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 
    } 
} 

但这种变异是复杂的(再创建一个FutureflatMap他们,NonFatal控制恢复)。我更倾向于使用parse方法的第一个变体(如果没有一些额外的期货和控制,它会变得更容易)。

+0

这是另一个很好的解决方案。非常感谢 – Mutaz