slick / slick

Slick (Scala Language Integrated Connection Kit) is a modern database query and access library for Scala
https://scala-slick.org/
BSD 2-Clause "Simplified" License
2.66k stars 610 forks source link

java.lang.ClassCastException: slick.jdbc.hikaricp.HikariCPJdbcDataSource$ cannot be cast to slick.jdbc.JdbcDataSourceFactory #1578

Open ronaldlee opened 8 years ago

ronaldlee commented 8 years ago

Hi,

I am getting this class cast exception: java.lang.ClassCastException: slick.jdbc.hikaricp.HikariCPJdbcDataSource$ cannot be cast to slick.jdbc.JdbcDataSourceFactory

I investigate further and narrow down to the slick.jdbc.JdbcDataSource.scala. Inside the JdbcDataSource object there is an inner function 'loadFactory' which loads the driver and casts it to the 'JdbcDataSourceFactory'. The line that throws such error is this:

clazz.getField("MODULE$").get(clazz).asInstanceOf[JdbcDataSourceFactory]

For some reason, the class loader that loads the driver is not the same as the one used to load the JdbcDataSourceFactory, and I believe that is the cause of this exception. I hack it by using the class loader of the JdbcDataSourceFactory to load the driver and it works:

  val yA = classOf[JdbcDataSourceFactory].getClassLoader
  val clazz = yA.loadClass(name)

I am using slick version 3.1.1, scala version 2.11.8. The project itself has a rather complex sbt set up since it hosts multiple sub services and pull in other packages as well. We write a Slick Plugin which is shared with other sub services setup in the sbt(s). I have another simpler project that only hosts a single service and doesn't use plugin for Slick config and that works fine.

Thanks. Ronald

MateuszKubuszok commented 7 years ago

Had the same error. Found out that this was due to SBT running all tests in the save JVM - after first run all next runs would end up in weird state when ClassLoaders got kind of mixed up, resulting in errors like one above. Solution in my case was to set fork in test := true.

hvesalai commented 6 years ago

I'm closing this as not relating to slick. SBT issue

balagez commented 6 years ago

I believe this is also a problem in Slick, not solely an SBT issue, in a way that Slick currently does not make interactive use of sbt test possible with certain test setup.

I had the same issue and tried the suggestion above to add fork in test := true but it didn't help. Then I tried explicitly passing the class loader to Database.forConfig which also didn't help, in a quite indeterministic way Slick sometimes used the wrong class loader.

Following the stack trace of the exception I got I noticed that JdbcBackend.createDatabase doesn't pass the class loader to Database.forConfig when it's called from DatabaseConfig.forConfig. So when DatabaseConfig.forConfig it explicitly called Slick might use different class loaders in DatabaseConfig and in JdbcDataSourceFactory that end up in a ClassCastException.

So while the root cause might be a combination of sbt, the test framework and interactive sbt use, there is in fact something Slick could do to help.

joshcough commented 2 years ago

I am getting this error after changing the slick hello sample to use postgres instead of the in-memory db. I added Test / fork := true. Is it certain that this is an SBT bug? I am not so sure.

nafg commented 2 years ago

@joshcough meaning that forking helped?

Also see https://www.scala-sbt.org/1.x/docs/In-Process-Classloaders.html, does setting any value of classLoaderLayeringStrategy help? (Be sure it's set in the right scope.)

joshcough commented 2 years ago

I apologize @nafg, I should have been more clear - the fork did not help. All I did was take the slick hello sample, I added Test / fork := true in build.sbt, and I changed application.conf to be this:

h2mem1 = {
  dataSourceClass = "org.postgresql.ds.PGSimpleDataSource"
  properties = {
    databaseName = "slick_sample"
    user = "joshuacough"
    password = "..."
  }
  numThreads = 10
}

Then running the tests gives me this:

sbt:sample-hello-slick> test
[info] TablesSuite:
[info] TablesSuite *** ABORTED ***
[info]   java.lang.ClassNotFoundException: slick.jdbc.hikaricp.HikariCPJdbcDataSource$
[info]   at java.base/java.lang.ClassLoader.findClass(ClassLoader.java:718)
[info]   at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:587)
[info]   at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520)
[info]   at slick.util.ClassLoaderUtil$$anon$1.loadClass(ClassLoaderUtil.scala:17)
[info]   at slick.jdbc.JdbcDataSource$.loadFactory$1(JdbcDataSource.scala:36)
[info]   at slick.jdbc.JdbcDataSource$.forConfig(JdbcDataSource.scala:41)
[info]   at slick.jdbc.JdbcBackend$DatabaseFactoryDef.forConfig(JdbcBackend.scala:341)
[info]   at slick.jdbc.JdbcBackend$DatabaseFactoryDef.forConfig$(JdbcBackend.scala:337)
[info]   at slick.jdbc.JdbcBackend$$anon$1.forConfig(JdbcBackend.scala:32)
[info]   at TablesSuite.$anonfun$new$1(TablesSuite.scala:21)
[info]   ...
nafg commented 2 years ago

@joshcough what version of slick?

joshcough commented 2 years ago

@nafg actually... I did this off the head of the main branch. I'll try the v3.3.3 tag.

joshcough commented 2 years ago

@nafg I managed to get it to work by using 3.3.3. Possible that my error just a weird thing that resulted from using main/HEAD. If you want, you should be able to reproduce this there by using the changes I listed above. But, if you simply closed this again, I wouldn't blame you.

nafg commented 2 years ago

If there's a regression since 3.3.3 we definitely want it fixed. Any chance you could submit a test case, or git bisect the bad commit?

Otherwise if you have a self-contained github repository that demonstrates the issue (working with 3.3.3 and failing with e.g. 3.4.0-M1) that would be very helpful.