Search code examples
scalaplayframeworkjvmguice

Play! 3.0 NoSuchMethodError: 'com.google.inject.Provider com.google.inject.util.Providers.guicify(javax.inject.Provider)'


I just returned to an old Play! framework project of mine which started in version 2.6.0 and has been updated to version 3.0.2

After fixing errors and updating the project to compile, I got it running! However when I hit localhost:9000 I immediately get a runtime error:

NoSuchMethodError: 'com.google.inject.Provider com.google.inject.util.Providers.guicify(javax.inject.Provider)'
play.api.inject.guice.GuiceableModuleConversions$$anon$4.$anonfun$configure$3(GuiceInjectorBuilder.scala:376)
     scala.Option.foreach(Option.scala:437)
     play.api.inject.guice.GuiceableModuleConversions$$anon$4.$anonfun$configure$2(GuiceInjectorBuilder.scala:375)
     play.api.inject.guice.GuiceableModuleConversions$$anon$4.$anonfun$configure$2$adapted(GuiceInjectorBuilder.scala:372)
     scala.collection.immutable.List.foreach(List.scala:334)
...
org.apache.pekko.stream.impl.fusing.MapAsyncUnordered$$anon$31.onPush(Ops.scala:1443)
...
org.apache.pekko.dispatch.Mailbox.exec(Mailbox.scala:253)
...
java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:165)

I've banged my head on this for days now mostly doing things like:

  • Updating / Changing the Scala version. Currently on 3.3.3

  • Clearing ~/.ivy2 and ~/Library/Caches/Coursier/v1/https/repo1.maven.org

  • build.sbt tweaks

Here is my build.sbt

name := """my-api"""
organization := "DEV LLC"

version := "1.0-SNAPSHOT"

scalaVersion := "3.3.3"

resolvers += "Typesafe Repository" at "https://mvnrepository.com/artifact/com.typesafe.akka/akka-stream"

libraryDependencies += filters
libraryDependencies += jdbc
libraryDependencies += ws
libraryDependencies += guice
// libraryDependencies += "com.google.inject" % "guice" % "4.2.0"
// libraryDependencies += "com.google.inject" % "guice" % "7.0.0"
libraryDependencies += "mysql" % "mysql-connector-java" % "5.1.24"
libraryDependencies += "org.json4s" %% "json4s-native" % "4.0.7"
libraryDependencies += "org.scalatestplus.play" %% "scalatestplus-play" % "7.0.0" % "test"
libraryDependencies += "org.docx4j" % "docx4j-export-fo" % "3.3.0"
libraryDependencies += "org.jsoup" % "jsoup" % "1.9.2"
libraryDependencies += "com.github.nscala-time" %% "nscala-time" % "2.32.0"
libraryDependencies += "com.google.firebase" % "firebase-admin" % "5.9.0"
libraryDependencies += "net.codingwell" %% "scala-guice" % "7.0.0"
libraryDependencies += "org.apache.commons" % "commons-email" % "1.5"

lazy val root = (project in file(".")).enablePlugins(PlayScala)

My theory has been that Play! is trying to call guicify at runtime on a dynamically loaded object, and failing with NoSuchMethod exception meaning that the version of Guice I have installed must not be the right version.

If that theory is right, then I'm still left perplexed because I have verified that my installed Guice version is 7.0 ~/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/com/google/inject/guice/7.0.0 and the guicify method was added in 4.x

Looking for any help or suggestions on how to move forward here as I am STUMPED!

EDIT: Here's the output of sbt dependencyTree

+-org.playframework:play-guice_3:3.0.2
[info]   | +-com.google.inject.extensions:guice-assistedinject:6.0.0
[info]   | | +-com.google.errorprone:error_prone_annotations:2.18.0 (evicted by: 2.21..
[info]   | | +-com.google.errorprone:error_prone_annotations:2.21.1
[info]   | | +-com.google.inject:guice:6.0.0 (evicted by: 7.0.0)
[info]   | | +-com.google.inject:guice:7.0.0
[info]   | |   +-aopalliance:aopalliance:1.0
[info]   | |   +-com.google.guava:guava:31.0.1-jre (evicted by: 32.1.3-jre)
[info]   | |   +-com.google.guava:guava:32.1.3-jre
[info]   | |   | +-com.google.code.findbugs:jsr305:3.0.2
[info]   | |   | +-com.google.errorprone:error_prone_annotations:2.21.1
[info]   | |   | +-com.google.guava:failureaccess:1.0.1
[info]   | |   | +-com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-w..
[info]   | |   | +-com.google.j2objc:j2objc-annotations:2.8
[info]   | |   | +-org.checkerframework:checker-qual:3.37.0
[info]   | |   | 
[info]   | |   +-jakarta.inject:jakarta.inject-api:2.0.1
[info]   | |   
[info]   | +-com.google.inject:guice:6.0.0 (evicted by: 7.0.0)
[info]   | +-com.google.inject:guice:7.0.0


+-net.codingwell:scala-guice_3:7.0.0
[info]   | +-com.google.inject:guice:7.0.0

Solution

  • Short answer: use/enforce Guice 6.x in your classpath. Play relies on 6.x for now and is not yet compatible with 7.x.

    Downgrading scala-guice to 6.x should be enough.


    The error you get is telling that the method does not exist. The thing to know is that the whole signature must be "compatible" for a method to be seen as existing.

    Especially here, the method com.google.inject.util.Providers.guicify(javax.inject.Provider) does indeed not exist. But com.google.inject.util.Providers.guicify(jakarta.inject.Provider) does.

    This is because of a major change in Java (EE, now Jakarta) ecosystem forcing renaming of some packages.

    Guice, relying on these packages, has released two versions supporting one or the other name:

    • 6.0.0 (supports javax.{inject,servlet,persistence}, mostly supports jakarta.inject)
    • 7.0.0 (supports jakarta.{inject,servlet,persistence})
    • (6.0.0 & 7.0.0 are equivalent except for their javax/jakarta support.)

    Version 7.x of Guice does not support anymore javax. packages.