对象 'cannot be cast' 在 Play for Scala 中使用 Hibernate

Object 'cannot be cast' using Hibernate in Play for Scala

我正在 运行在 Play for Scala 2.5 中使用 Hibernate 5.x。 Hibernate 访问 SAP Hana 数据库。

当我触摸代码并自动编译时出现问题。代码编译后,当我 运行 应用程序时,如果代码调用 Hibernate 函数,我会在 admin.dates.DateHib cannot be cast to admin.dates.DateHib 下面得到异常,其中 DateHib 是带注释的 Hibernate class。请注意,我既不更改 Hibernate 对象也不更改使用 Hibernate 对象的函数。不过,当我 运行 编辑代码后,我得到了 cannot be cast 错误。

解决方法是重启Play,但我每次触摸代码都无法重启Play。

我不确定它是否与这个问题有任何关系,但我运行宁在同一个应用程序 Slick 3.1 访问 MySql。

有什么想法吗?

这是失败的代码:

 def findLastDayHoliday (month: Int, year: Int) = {
     val session = HibernateUtil.sessionFactoryBank.openSession
     try {
         val query = session.createQuery("from DateHib where month=:month and year=:year")
         query.setMaxResults(1)
         query.setParameter("year", year)
         query.setParameter("month", month)
         val list = query.list.asScala.toList.map(_.asInstanceOf[DateHib])
         if (list.length>0)
             Some(list(0))
         else
              None
      }
      catch {
        case e:Exception => throw new Exception ("Failure: " + e.getMessage)
      }
      finally session.close
   }

这是个例外:

play.api.http.HttpErrorHandlerExceptions$$anon: Execution exception[[Exception: Failure in findLastDayHoliday: admin.dates.DateHib cannot be cast to admin.dates.DateHib]]
        at play.api.http.HttpErrorHandlerExceptions$.throwableToUsefulException(HttpErrorHandler.scala:293)
        at play.api.http.DefaultHttpErrorHandler.onServerError(HttpErrorHandler.scala:220)
        at play.api.GlobalSettings$class.onError(GlobalSettings.scala:160)
        at play.api.DefaultGlobal$.onError(GlobalSettings.scala:188)
        at play.api.http.GlobalSettingsHttpErrorHandler.onServerError(HttpErrorHandler.scala:100)
        at play.core.server.netty.PlayRequestHandler$$anonfun$$anonfun$apply.applyOrElse(PlayRequestHandler.scala:100)
        at play.core.server.netty.PlayRequestHandler$$anonfun$$anonfun$apply.applyOrElse(PlayRequestHandler.scala:99)
        at scala.concurrent.Future$$anonfun$recoverWith.apply(Future.scala:344)
        at scala.concurrent.Future$$anonfun$recoverWith.apply(Future.scala:343)
        at scala.concurrent.impl.CallbackRunnable.run(Promise.scala:32)
Caused by: java.lang.Exception: Failure in findLastDayHoliday: admin.dates.DateHib cannot be cast to admin.dates.DateHib
        at admin.dates.DateObjDAO.findLastDayHoliday(DateObjDAO.scala:126)
        at ds.formula.process.RunFormula.getLastDayHoliday(RunFormula.scala:665)
        at ds.formula.process.RunFormula.getFromToDates(RunFormula.scala:610)
        at ds.formula.process.RunFormula.run(RunFormula.scala:145)
        at ds.formula.process.RunFormula.doTest(RunFormula.scala:69)
        at ds.formula.process.RunFormula$$anonfun$test.apply(RunFormula.scala:61)
        at ds.formula.process.RunFormula$$anonfun$test.apply(RunFormula.scala:59)
        at login.Authentication$LoggedAction$$anonfun$invokeBlock.apply(LoggedAction.scala:39)
        at login.Authentication$LoggedAction$$anonfun$invokeBlock.apply(LoggedAction.scala:34)
        at scala.concurrent.Future$$anonfun$flatMap.apply(Future.scala:251)

我认为 cchantep 是对的。每次播放重新加载您的应用程序时,它都会使用不同的类加载器。

我看到可能会发生两件事:

  1. 您正在使用一些使用 play 最初创建的类加载器加载的单例,当 play 重新加载这些单例时,这些单例没有被破坏,导致您看到的那种问题。
  2. 您使用了一些服务,您应该在播放重新加载时关闭并重新启动,但您没有这样做,这会导致与上述第 1 点相同的问题。

但首先,让我们确保以上内容是正确的,看看如何更准确地诊断:我会在失败代码中添加日志条目,以打印不同对象中使用的类加载器。

     val list = query.list.asScala.toList.map { e => 
       log.debug("Class loaded with: " + e.getClass.getClassLoader)
       log.debug("Current class loader: " + classOf[DateHib].getClassLoader)
       e.asInstanceOf[DateHib]
     }

我的猜测是当你第一次启动你的应用程序时打印的类加载器是一样的,但是在播放重新加载后,第一个打印的类加载器没有改变,但第二个是一个新的实例......试一试。

至于解决这些问题,您应该查看 play 的生命周期挂钩:https://www.playframework.com/documentation/2.6.x/ScalaDependencyInjection#Stopping/cleaning-up