2015-11-11 92 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