Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

InjectedController trait not working with scala 3 #12272

Open
ThomasGrt opened this issue Dec 13, 2023 · 9 comments
Open

InjectedController trait not working with scala 3 #12272

ThomasGrt opened this issue Dec 13, 2023 · 9 comments

Comments

@ThomasGrt
Copy link

Play Version

Play 3.0.0

API

Scala 3

Operating System

Fedora 38

JDK

openjdk version "17.0.9" 2023-10-17
openjdk version "11.0.21" 2023-10-17

Library Dependencies

None

Expected Behavior

  1. Controller inheriting from InjectedController should serve result

Actual Behavior

  1. when calling route to controller via browser or test we get an error
ERROR p.a.h.DefaultHttpErrorHandler - 

! @83p3df7p7 - Internal server error, for (GET) [/] ->
 
play.api.http.HttpErrorHandlerExceptions$$anon$1: Execution exception[[NoSuchElementException: ControllerComponents not set! Call setControllerComponents or create the instance with dependency injection.]]
        at play.api.http.HttpErrorHandlerExceptions$.convertToPlayException$$anonfun$2(HttpErrorHandler.scala:405)
        at scala.Option.map(Option.scala:242)
        at play.api.http.HttpErrorHandlerExceptions$.convertToPlayException(HttpErrorHandler.scala:406)
        at play.api.http.HttpErrorHandlerExceptions$.throwableToUsefulException(HttpErrorHandler.scala:390)
        at play.api.http.DefaultHttpErrorHandler.onServerError(HttpErrorHandler.scala:267)
        at play.core.server.Server$$anon$1.applyOrElse(Server.scala:116)
        at play.core.server.Server$$anon$1.applyOrElse(Server.scala:112)
        at scala.runtime.AbstractPartialFunction.apply(AbstractPartialFunction.scala:35)
        at play.core.server.Server$.getHandlerFor(Server.scala:137)
        at play.core.server.PekkoHttpServer.handleRequest(PekkoHttpServer.scala:355)
Caused by: java.util.NoSuchElementException: ControllerComponents not set! Call setControllerComponents or create the instance with dependency injection.
        at play.api.mvc.InjectedController.fallbackControllerComponents(Controller.scala:202)
        at play.api.mvc.InjectedController.fallbackControllerComponents$(Controller.scala:182)
        at controllers.HomeController.fallbackControllerComponents(HomeController.scala:13)
        at play.api.mvc.InjectedController.controllerComponents(Controller.scala:186)
        at play.api.mvc.InjectedController.controllerComponents$(Controller.scala:182)
        at controllers.HomeController.controllerComponents(HomeController.scala:13)
        at play.api.mvc.BaseController.Action(Controller.scala:171)
        at play.api.mvc.BaseController.Action$(Controller.scala:158)
        at controllers.HomeController.Action(HomeController.scala:13)
        at controllers.HomeController.index(HomeController.scala:22)

Reproducible Test Case

I reproduced this bug with some minor tweaks to play-samples/play-scala-hello-world-tutorial code.

  1. In HomeController replace AbstractController with InjectedController
-class HomeController @Inject()(cc: ControllerComponents) extends AbstractController(cc) {
+class HomeController @Inject()() extends InjectedController {
  1. Force use of scala 3 (by default project user scala 2.13)
     crossScalaVersions := Seq("2.13.12", "3.3.1"),
-    scalaVersion := crossScalaVersions.value.head,
+    scalaVersion := "3.3.1",
  1. Launch app with sbt run
  2. Access http://localhost:9000/ to get the error (this is the one listed in the previous step)

Note: exact same code works if you switch back to scala "2.13.12" and Play serves the "Play Hello World Web Tutorial" page

@mkurz
Copy link
Member

mkurz commented Dec 14, 2023

Can confirm, taking a look already. Thanks a lot for the report!

@mkurz mkurz added this to the 3.0.1 milestone Dec 14, 2023
@mkurz
Copy link
Member

mkurz commented Dec 14, 2023

Pretty sure I nailed it down:
When decompiling HomeController.class (using javap -v) the method signature for setControllerComponents is different for Scala 2.13 and Scala 3.

Scala 2.13:

  public void setControllerComponents(play.api.mvc.ControllerComponents);
    descriptor: (Lplay/api/mvc/ControllerComponents;)V
    flags: (0x0001) ACC_PUBLIC

Scala 3:

  public void setControllerComponents(play.api.mvc.ControllerComponents);
    descriptor: (Lplay/api/mvc/ControllerComponents;)V
    flags: (0x1041) ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC

So you see Scala 3 marks the method as synthetic bridge method (ACC_BRIDGE and ACC_SYNTHETIC).

Guice however ignores such methods:
https://github.com/google/guice/blob/f095cad8aa7b59abafacc4d4461ddfc77be83667/core/src/com/google/inject/spi/InjectionPoint.java#L819-L841

Need to find a workaround...

@ThomasGrt
Copy link
Author

Thanks for the quick feedback and for your work on Play! 👏🏻

Seems pretty low level stuff (scala compiler...), I don't know why they changed this in scala 3.
Hope that, as you said, you can find a workaround.

One can still use AbstractController instead of InjectedController but if there's a way to make it work that would be better.

@PromanSEW
Copy link
Contributor

This is definitely regression / breaking change in Scala 3 compiler

@mkurz
Copy link
Member

mkurz commented Dec 14, 2023

So I tried lots of stuff, but couldn't make it work, and at this point I also believe this is a bug in the Scala 3 compiler, but I am not 100% sure, so I leave the judgment to the experts:

@mkurz
Copy link
Member

mkurz commented Dec 19, 2023

So according to scala/scala3#19270 (comment) this is a problem in the Scala 3 compiler. Let's leave the things how they are currently and let's hope they fix it with Scala 3.3.3 (3.3.2 is in RC phase already, so no chance anymore)

@ThomasGrt
Copy link
Author

Thanks for the follow up!
Let's wait for the fix.

@mkurz mkurz removed this from the 2.9.2 / 3.0.2 milestone Feb 27, 2024
@aumann
Copy link
Contributor

aumann commented Apr 5, 2024

Should this be added to the migration notes? It hit us in production (we only used the InjectedController in one rarely visited spot 🙈 ), and might hit others migrating to play 2.9/3.0.

If there's interest I would open a doc pull-request to add a short warning to: https://www.playframework.com/documentation/2.9.x/Scala3Migration

@mkurz
Copy link
Member

mkurz commented Apr 8, 2024

If there's interest I would open a doc pull-request to add a short warning

@aumann Yes sure, please go for it, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants