【问题标题】:Object 'cannot be cast' using Hibernate in Play for Scala在 Play for Scala 中使用 Hibernate 的对象“无法转换”
【发布时间】:2017-08-18 04:46:36
【问题描述】:

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

当我触摸代码并且 Play 自动编译时会出现问题。在代码编译之后,当我运行应用程序时,如果代码调用 Hibernate 函数,我会在admin.dates.DateHib cannot be cast to admin.dates.DateHib 下面得到异常,其中DateHib 是一个 Hibernate 注释类。请注意,我既不会更改 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$1: 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$2$$anonfun$apply$1.applyOrElse(PlayRequestHandler.scala:100)
        at play.core.server.netty.PlayRequestHandler$$anonfun$2$$anonfun$apply$1.applyOrElse(PlayRequestHandler.scala:99)
        at scala.concurrent.Future$$anonfun$recoverWith$1.apply(Future.scala:344)
        at scala.concurrent.Future$$anonfun$recoverWith$1.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$1.apply(RunFormula.scala:61)
        at ds.formula.process.RunFormula$$anonfun$test$1.apply(RunFormula.scala:59)
        at login.Authentication$LoggedAction$$anonfun$invokeBlock$1.apply(LoggedAction.scala:39)
        at login.Authentication$LoggedAction$$anonfun$invokeBlock$1.apply(LoggedAction.scala:34)
        at scala.concurrent.Future$$anonfun$flatMap$1.apply(Future.scala:251)

【问题讨论】:

  • 猜测一个类加载器问题,导致引用使用同一类的不同版本(因此同一类的不同 Class 实例)

标签: scala hibernate playframework playframework-2.0


【解决方案1】:

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

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

  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

【讨论】:

  • 这是我打印日志时得到的,显然版本不同?Class loaded with: ReloadableClassLoader(v1){file:/C:/visual/apps/target/scala-2.11/classes/} Current class loader: ReloadableClassLoader(v2){file:/C:/visual/apps/target/scala-2.11/classes/}
  • 你是对的,我在启动时加载了一个实现 Quartz akka-quartz-scheduler 的 Play 类,当 Play 启动时,调度程序被触发并在后台运行以在需要时启动任何进程。显然我需要在重新加载 Play 时卸载调度程序?
  • 是的,你最终使用了 2 个不同的类加载器。是的,您需要卸载该调度程序。但是,由于 playframework 关闭了自己的 actor 系统,我不确定您的调度程序发生了什么。你在使用play的演员系统吗?你是通过调度程序调用的findLastDayHoliday 函数吗?
  • 我正在使用 play 的演员系统。调度程序调用findLastDayHoliday,引发错误的函数也是如此。
猜你喜欢
  • 2018-02-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-28
  • 2016-11-13
  • 1970-01-01
相关资源
最近更新 更多