如何在sbt中指定类路径运行代码?自定义Slick代码生成器报错求助
Slick自定义代码生成异常解决方案
问题根因
ClassNotFoundException: scala.Serializable报错原因:你自行构造的classpath取自主项目的Compile / dependencyClasspath,仅包含主项目依赖,没有包含构建脚本(project目录下代码)对应的类路径及匹配版本的Scala标准库,导致Scala核心类缺失。ClassNotFoundException: ExampleCodeGenerator报错原因:Slick的SourceCodeGenerator.main方法内部使用当前线程上下文类加载器加载自定义生成器,而sbt执行任务的默认上下文类加载器是主项目的类加载器,无法识别project目录下的构建类,即使sbt脚本本身能访问到该类也会加载失败。
无需拆分子项目的解决方案
方案一(推荐):直接实例化自定义生成器,绕过Slick的反射加载逻辑
直接在sbt任务中手动获取数据库模型、实例化你编写的ExampleCodeGenerator,完全避开类加载问题:
import slick.codegen.SourceCodeGenerator import slick.jdbc.JdbcProfile // 注册代码生成任务 val generateSlickCode = taskKey[Unit]("Generate Slick entity code with custom generator") generateSlickCode := { // 替换为你自己的配置参数 val outputDir = (Compile / sourceManaged).value / "slick-gen" val slickProfile = "slick.jdbc.MySQLProfile" val jdbcDriver = "com.mysql.cj.jdbc.Driver" val dbUrl = "jdbc:mysql://localhost:3306/your_database" val dbUser = "your_username" val dbPass = "your_password" val targetPackage = "com.yourorg.model" val db = slick.jdbc.JdbcBackend.Database.forURL(dbUrl, dbUser, dbPass, driver = jdbcDriver) try { // 同步获取数据库元数据模型 val model = db.run( slick.jdbc.meta.MTable.getTables(None, None, None, Some(Seq("TABLE", "VIEW"))) .flatMap(tables => JdbcProfile.createModel(tables)) ).await(scala.concurrent.duration.Duration.Inf) // 直接实例化自定义生成器,无需走反射加载 val generator = new ExampleCodeGenerator(model) generator.writeToFile(slickProfile, outputDir.getPath, targetPackage) } finally { db.close() } }
注意:需要在
project/build.sbt中添加Slick代码生成和数据库驱动依赖,确保构建脚本能访问到对应类:
libraryDependencies ++= Seq( "com.typesafe.slick" %% "slick-codegen" % "你的Slick版本号", "你的数据库驱动组名" % "驱动artifactId" % "驱动版本号" )
方案二:修改线程上下文类加载器适配Slick的加载逻辑
如果一定要使用Slick官方提供的main方法调用逻辑,只需要在调用前将当前线程的上下文类加载器替换为自定义生成器对应的类加载器即可:
// 替换上下文类加载器为构建类的类加载器 Thread.currentThread.setContextClassLoader(classOf[ExampleCodeGenerator].getClassLoader) // 再调用官方main方法就不会找不到自定义生成器 slick.codegen.SourceCodeGenerator.main( Array(slickProfile, jdbcDriver, dbUrl, outputDir.getPath, targetPackage, dbUser, dbPass, "true", classOf[ExampleCodeGenerator].getName, "true") )
内容的提问来源于stack exchange,提问作者Mike
相关产品推荐
相关产品推荐

