【问题标题】:Need help handling IllegalArgumentException in reactivemongo需要帮助处理反应蒙戈中的 IllegalArgumentException
【发布时间】:2015-11-12 18:15:23
【问题描述】:

以下代码尝试使用 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)
  }

【问题讨论】:

    标签: scala reactivemongo


    【解决方案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)
      }
    

    【讨论】:

    • 谢谢,编译器现在感觉好多了。但我无法捕捉到异常。说val resultFuture = get(BSONDocument("_id" -> BSONObjectID(id))) .recover { case _ => None } resultFuture.onFailure 和 resultFuture.onSuccess 都没有达到/匹配。如何匹配recover case _ => None 模式?
    • collection.find 是抛出 IllegalArgumentException 还是返回失败的 Future
    • 仍然抛出IllegalArgumentException
    • 我已经更新了我的答案,让get 返回失败的Future 而不是抛出IllegalArgumentException
    • 使用了您的代码,但仍然抛出未处理的异常!你怎么看?
    【解决方案2】:

    我理解你的问题,

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

    在您的代码中,Scala 在调用 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 方法的第一个变体(如果没有一些额外的期货和控制,它会更容易)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-07-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多