scala – SBT / Play2多项目设置不包括运行/测试中类路径中的依
我有以下SBT / Play2多项目设置:
import sbt._ import Keys._ import PlayProject._ object ApplicationBuild extends Build { val appName = "traveltime-api" val appVersion = "1.0" val appDependencies = Seq( // Google geocoding library "com.google.code.geocoder-java" % "geocoder-java" % "0.9",// Emailer "org.apache.commons" % "commons-email" % "1.2",// CSV generator "net.sf.opencsv" % "opencsv" % "2.0","org.scalatest" %% "scalatest" % "1.7.2" % "test","org.scalacheck" %% "scalacheck" % "1.10.0" % "test","org.mockito" % "mockito-core" % "1.9.0" % "test" ) val lib = RootProject(file("../lib")) val chiShape = RootProject(file("../chi-shape")) lazy val main = PlayProject( appName,appVersion,appDependencies,mainLang = SCALA ).settings( // Add your own project settings here resolvers ++= Seq( "Sonatype Snapshots" at "http://oss.sonatype.org/content/repositories/snapshots","Sonatype Releases" at "http://oss.sonatype.org/content/repositories/releases" ),// Scalatest compatibility testOptions in Test := Nil ).aggregate(lib,chiShape).dependsOn(lib,chiShape) } 正如您所看到的,这个项目取决于两个独立的子项目:lib和chiShape. 现在编译工作正常 – 所有源都正确编译.但是,如果我尝试运行或测试,那么运行时的任务都没有来自加载类路径的子项目的类,并且事情会因NoClassFound异常而变得混乱. 例如 – 我的应用程序必须从文件加载序列化数据,它是这样的:测试启动FakeApplication,它尝试加载数据和繁荣: [info] CsvGeneratorsTest: [info] #markerFilterCsv [info] - should fail on bad json *** FAILED *** [info] java.lang.ClassNotFoundException: com.library.Node [info] at java.net.URLClassLoader$1.run(URLClassLoader.java:366) [info] at java.net.URLClassLoader$1.run(URLClassLoader.java:355) [info] at java.security.AccessController.doPrivileged(Native Method) [info] at java.net.URLClassLoader.findClass(URLClassLoader.java:354) [info] at java.lang.ClassLoader.loadClass(ClassLoader.java:423) [info] at java.lang.ClassLoader.loadClass(ClassLoader.java:356) [info] at java.lang.Class.forName0(Native Method) [info] at java.lang.Class.forName(Class.java:264) [info] at java.io.ObjectInputStream.resolveClass(ObjectInputStream.java:622) [info] at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1593) [info] ... 奇怪的是,stage在staged /中创建了一个目录结构,其中包含chi-shapes_2.9.1-1.0.jar和lib_2.9.1-1.0.jar. 如何让我的运行时/测试配置将子项目导入类路径? 更新: 我已将以下代码添加到Global#onStart: override def onStart(app: Application) { println(app) ClassLoader.getSystemClassLoader.asInstanceOf[URLClassLoader].getURLs. foreach(println) throw new RuntimeException("foo!") } 当我启动测试时,类路径的填充非常糟糕,至少可以说:) FakeApplication(.,sbt.classpath.ClasspathUtilities$$anon$1@182253a,List(),Map(application.load-data -> test,mailer.smtp.test-mode -> true)) file:/home/arturas/Software/sdks/play-2.0.3/framework/sbt/sbt-launch.jar [info] CsvGeneratorsTest: 当启动分阶段的应用程序时,有很多东西,它应该如何:) $target/start Play server process ID is 29045 play.api.Application@1c2862b file:/home/arturas/work/traveltime-api/api/target/staged/jul-to-slf4j.jar 这很奇怪,因为我想在类路径中应该至少测试一下jar? 解决方法
好像我已经解决了.
罪魁祸首是ObjectInputStream默认忽略线程本地类加载器,只使用系统类加载器. 所以我改变了: def unserialize[T](file: File): T = { val in = new ObjectInputStream(new FileInputStream(file)) try { in.readObject().asInstanceOf[T] } finally { in.close } } 至: /** * Object input stream which respects thread local class loader. * * TL class loader is used by SBT to avoid polluting system class loader when * running different tasks. */ class TLObjectInputStream(in: InputStream) extends ObjectInputStream(in) { override protected def resolveClass(desc: ObjectStreamClass): Class[_] = { Option(Thread.currentThread().getContextClassLoader).map { cl => try { return cl.loadClass(desc.getName)} catch { case (e: java.lang.ClassNotFoundException) => () } } super.resolveClass(desc) } } def unserialize[T](file: File): T = { val in = new TLObjectInputStream(new FileInputStream(file)) try { in.readObject().asInstanceOf[T] } finally { in.close } } 我的班级没有发现问题就消失了! 感谢How to put custom ClassLoader to use?和http://tech-tauk.blogspot.com/2010/05/thread-context-classlaoder-in.html关于反序列化和线程本地类加载器的有用见解. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |