-
-
Notifications
You must be signed in to change notification settings - Fork 4.1k
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
Correctly handle "_root_." prefix in routes file (needed for namespaceReverseRouter) #10153
Correctly handle "_root_." prefix in routes file (needed for namespaceReverseRouter) #10153
Conversation
@@ -68,15 +68,15 @@ object HandlerInvokerFactory { | |||
|
|||
private def loadJavaControllerClass(handlerDef: HandlerDef): Class[_] = { | |||
try { | |||
handlerDef.classLoader.loadClass(handlerDef.controller) | |||
handlerDef.classLoader.loadClass(handlerDef.controller.stripPrefix("_root_.")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This has nothing to do with the fix this pull request is about, however we should also strip _root_.
here, because _root_
is a Scala feature and the Java classloader can not load classes with _root_.
prefixed via the loadClass(...)
method.
You can test this in jshell
:
jshell> Thread.currentThread().getContextClassLoader().loadClass("java.lang.Runtime")
$1 ==> class java.lang.Runtime
works, however prefixing fails;
jshell> Thread.currentThread().getContextClassLoader().loadClass("_root_.java.lang.Runtime")
| Exception java.lang.ClassNotFoundException: _root_.java.lang.Runtime
| at URLClassLoader.findClass (URLClassLoader.java:471)
| at DefaultLoaderDelegate$RemoteClassLoader.findClass (DefaultLoaderDelegate.java:154)
| at ClassLoader.loadClass (ClassLoader.java:588)
| at ClassLoader.loadClass (ClassLoader.java:521)
| at (#2:1)
@@ -181,7 +181,7 @@ object InjectedRoutesGenerator extends RoutesGenerator { | |||
routes: List[Route], | |||
namespaceReverseRouter: Boolean | |||
) = { | |||
routes.groupBy(_.call.packageName).map { | |||
routes.groupBy(_.call.packageName.map(_.stripPrefix("_root_."))).map { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For ReverseRoutes.scala
.
@@ -209,7 +209,7 @@ object InjectedRoutesGenerator extends RoutesGenerator { | |||
routes: List[Route], | |||
namespaceReverseRouter: Boolean | |||
) = { | |||
routes.groupBy(_.call.packageName).map { | |||
routes.groupBy(_.call.packageName.map(_.stripPrefix("_root_."))).map { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For JavaScriptReverseRoutes.scala
.
@@ -236,7 +236,7 @@ object InjectedRoutesGenerator extends RoutesGenerator { | |||
rules: List[Rule], | |||
namespaceReverseRouter: Boolean | |||
) = { | |||
rules.collect { case r: Route => r }.groupBy(_.call.packageName).map { | |||
rules.collect { case r: Route => r }.groupBy(_.call.packageName.map(_.stripPrefix("_root_."))).map { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For routes.java
.
it("should provide the GET method for assets", function() { | ||
var data = jsRoutes.controllers.Assets.versioned(); | ||
assert.equal("GET", data.method); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just make sure this pull request did not break the any existing (js) reverse router.
@@ -72,7 +72,8 @@ GET /routestest controllers.Application.routetest(yield) | |||
# Test for default values for scala keywords | |||
GET /routesdefault controllers.Application.routedefault(type ?= "x") | |||
|
|||
GET /public/*file controllers.Assets.versioned(path="/public", file: controllers.Assets.Asset) | |||
# Let's prefix with "_root_." (should not make any difference however because namespaceReverseRouter is not set in build.sbt) | |||
GET /public/*file _root_.controllers.Assets.versioned(path="/public", file: controllers.Assets.Asset) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adding _root_
here does not make any difference, however I want to add it so it's tested once as well.
8e730c7
to
6561563
Compare
6561563
to
28f1989
Compare
This seems like a good argument to move |
That would help as well. However adding support for the Did you have a look at my PR? Should be good to go I think. |
@Mergifyio backport 2.8.x |
Command
|
Thanks @gmethvin! |
Correctly handle "_root_." prefix in routes file (needed for namespaceReverseRouter) (bp #10153)
First of all:
I have a reproducer: https://github.com/mkurz/play-namespace-reverse-router-bug/tree/reproducer
Now step by step:
If you set up a very very simple Play project (with latest version 2.8.1) with just this simple
conf/routes
file that only contains the route to the build-in assets controller:and with the config
namespaceReverseRouter
set totrue
inbuild.sbt
:the project does not compile:
You can test this yourself by checking out the
reproducer
branch of my reproducer project.To makes things easy I also uploaded the generated files from the
target
folder, see this branch.The line causing the problem is:
which can be found twice, here and here in the generated
Routes.scala
.Now look at the file/package structure that gets generated:
Seen from
Routes.scala
the rootcontrollers
package is shadowed by therouter.controllers
package, which of course does not containcontrollers.Assets
.The most obvious solution for problems like this is to add Scala's
_root_.
prefix to the package:(See the
master
branch, where I applied this change).This does work, project compiles, however it is not really nice.
First of all there are some annoying and ugly warnings:
Second, look at the file/package structure:
As you can see to generate reverse routes you would have to write
router._root_.controllers.MyController.myAction()
which is not what we wanted to achieve here. We wanted to use the rootAssets
class inRoutes.scala
nothing more:I uploaded this generated files to the
generated-with-_root_
branch. Also see the diff (be aware files moved).So basically what we want here is to only change
Routes.scala
to prepend_root_.
to the variables where necessary, but generate all other files like before.And this is what this pull request does: It ignore the
_root_.
prefix for the reverse routers.With this fix applied, this is what changes now in the generated files: diff.
Besides adding comprehensive scripted tests, I also applied this fix to a fairly large project of mine which also has javascript reverse routes (also for assets) and it works like a charm.
One last thing: Usually what you want to do when adding
namespaceReverseRouter := true
is to move controllers fromapp/controllers/
toapp/router/controller/
. However for the build-in Assets class this is not possible because obviously you can not move the file, because it's in the play jar...