Description
Compiler version
3.3.1
Reproducer
(Sorry I don't have time to come up with a minimized code example)
git clone [email protected]:mkurz/play-samples.git
cd play-samples/play-scala-hello-world-tutorial
git checkout issue-12272
sbt run
# In another terminal (or use a browser)
curl localhost:9000
You will see the Play app fails with an exception.
However the exact same application works just fine with Scala 2.13.12 (++2.x ; run
).
Description why the problem occurs:
Our controller class extends from the InjectedController
trait (line):
class HomeController @Inject()() extends InjectedController {
The InjectedController
trait defines a concrete method setControllerComponents
which should get components
injected by Guice (line)
@Inject
def setControllerComponents(components: ControllerComponents): Unit = {
_components = components
}
Problem: In Scala 2 Guice does inject components
and calls the method, in Scala 3 it does not.
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
The question I have is: Why is that concrete method marked as ACC_BRIDGE
and ACC_SYNTHETIC
in Scala 3? Is that a bug? If not, how can I make our code work? Are there any docs or notes on that behaviour?
Thanks!
Originally posted by @ThomasGrt in playframework/playframework#12272