--
You received this message because you are subscribed to the Google Groups "Play Framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email to play-framework+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/play-framework/2d126d4b-1211-47f8-9885-429e07c75ca6%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Hi Alexis,There are basically two strategies to have "request-scoped" objects.The first way is to store the request state in a ThreadLocal. Normally in a servlet-based framework this is really easy to do, because we know each request has its own thread. In Play that's not the case, since Play is non-blocking and may reuse the same thread for multiple simultaneous requests. That means if we use a ThreadLocal we need to make sure it's set properly whenever we execute something on that thread. Since in the Java API the Play already sets the Http.Context thread local that seems like the natural place to start. This is what the custom scope in the linked StackOverflow answer was using. You also need to make sure that thread local state is propagated to any threads where you want to use it, e.g. using the HttpExecutionContext helper.Another approach is to create a child injector for each request and make the controllers themselves request scoped. That means we create a new injector that inherits the bindings from the parent injector, also adding bindings for the request and other request-scoped components. Now the request-scoped dependencies can be injected into your controllers like any other dependency.I was trying to find a generic solution to do this in Play (as you can see from that thread), but didn't have time to come up with a complete solution. You can see my work-in-progress pull request here: https://github.com/playframework/playframework/pull/6798. There are not really any changes to Play itself there so that code should already be usable as a starting point in your own application.Greg
On Sat, Sep 2, 2017 at 10:26 PM, Alexis Hernandez <alexi...@gmail.com> wrote:
Hi,
I'm trying to get dependency injection working on request based scopes, I've read some previous threads about this, these were the more useful:
- https://groups.google.com/forum/#!topic/google-guice/qZqkaWPkhoo
- https://stackoverflow.com/a/34981902/3211175
Sadly, I haven't been able to get the working on Scala, I couldn't even find 'Http.Context.current' on Scala API to give a try to the code given in StackOverflow..
Have any of you been able to get this working? Any guidance would be appreciated.
Thanks.
--
You received this message because you are subscribed to the Google Groups "Play Framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email to play-framewor...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/play-framework/2d126d4b-1211-47f8-9885-429e07c75ca6%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Hi Alexis,There are basically two strategies to have "request-scoped" objects.The first way is to store the request state in a ThreadLocal. Normally in a servlet-based framework this is really easy to do, because we know each request has its own thread. In Play that's not the case, since Play is non-blocking and may reuse the same thread for multiple simultaneous requests. That means if we use a ThreadLocal we need to make sure it's set properly whenever we execute something on that thread. Since in the Java API the Play already sets the Http.Context thread local that seems like the natural place to start. This is what the custom scope in the linked StackOverflow answer was using. You also need to make sure that thread local state is propagated to any threads where you want to use it, e.g. using the HttpExecutionContext helper.Another approach is to create a child injector for each request and make the controllers themselves request scoped. That means we create a new injector that inherits the bindings from the parent injector, also adding bindings for the request and other request-scoped components. Now the request-scoped dependencies can be injected into your controllers like any other dependency.I was trying to find a generic solution to do this in Play (as you can see from that thread), but didn't have time to come up with a complete solution. You can see my work-in-progress pull request here: https://github.com/playframework/playframework/pull/6798. There are not really any changes to Play itself there so that code should already be usable as a starting point in your own application.Greg
On Sat, Sep 2, 2017 at 10:26 PM, Alexis Hernandez <alexi...@gmail.com> wrote:
Hi,
I'm trying to get dependency injection working on request based scopes, I've read some previous threads about this, these were the more useful:
- https://groups.google.com/forum/#!topic/google-guice/qZqkaWPkhoo
- https://stackoverflow.com/a/34981902/3211175
Sadly, I haven't been able to get the working on Scala, I couldn't even find 'Http.Context.current' on Scala API to give a try to the code given in StackOverflow..
Have any of you been able to get this working? Any guidance would be appreciated.
Thanks.
--
You received this message because you are subscribed to the Google Groups "Play Framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email to play-framewor...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/play-framework/2d126d4b-1211-47f8-9885-429e07c75ca6%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
To unsubscribe from this group and stop receiving emails from it, send an email to play-framework+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/play-framework/66117ee3-ef9d-4ddd-84a6-3bf03559cf27%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Hi Greg,
I've looked to your pull request, its been quite useful! turns out that I was looking to the wrong part for creating the child injector.
I was able to get request based objects created, these objects should not depend in anything that is coming from the request, do you have any idea for injecting the RequestHeader into MyRequestModule? My current idea would be to modify RequestScopedRouter to instantiate the guice modules passing the request instead of receiving the guice modules instances.
To unsubscribe from this group and stop receiving emails from it, send an email to play-framework+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/play-framework/efdf492d-b816-4186-ba27-e9dc3cbac7e9%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
To view this discussion on the web visit https://groups.google.com/d/msgid/play-framework/efdf492d-b816-4186-ba27-e9dc3cbac7e9%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
To unsubscribe from this group and stop receiving emails from it, send an email to play-framework+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/play-framework/761c3b5f-469e-4f5e-bbe1-5fca19804a47%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
To view this discussion on the web visit https://groups.google.com/d/msgid/play-framework/761c3b5f-469e-4f5e-bbe1-5fca19804a47%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
def handlerForRequest(request: RequestHeader): (RequestHeader, Handler)To view this discussion on the web visit https://groups.google.com/d/msgid/play-framework/761c3b5f-469e-4f5e-bbe1-5fca19804a47%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
/**
* Provide a router that is scoped to this request.
*/
def routerForRequest(request: RequestHeader): Router = {
val childInjector = injectorWithRequest
.createChildInjector(requestScopedModules: _*)
childInjector
.getInstance(routerClassTag.runtimeClass)
.asInstanceOf[T]
.withPrefix(prefix)
}To view this discussion on the web visit https://groups.google.com/d/msgid/play-framework/761c3b5f-469e-4f5e-bbe1-5fca19804a47%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Hi Greg,
Could you explain how this method works (from RequestScopedRouter)? We are creating the Router with the child injector but how does Play knows about the child injector in order to create new instances from it?
/**
* Provide a router that is scoped to this request.
*/
def routerForRequest(request: RequestHeader): Router = {
val childInjector = injectorWithRequest
.createChildInjector(requestScopedModules: _*)
childInjector
.getInstance(routerClassTag.runtimeClass)
.asInstanceOf[T]
.withPrefix(prefix)
}
Also, as I understand, this approach doesn't work for injecting request-scoped objects in filters because the filters seems to be singletons, in this case, is there a way to set filters to be created every time they are used?
To unsubscribe from this group and stop receiving emails from it, send an email to play-framework+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/play-framework/040b7846-3d35-4530-8a07-f3fa6f050d10%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
// MyRequestScopedRequestHandler.scala
import javax.inject.Inject
import com.google.inject.{AbstractModule, Injector}
import play.api.http.{DefaultHttpRequestHandler, HttpRequestHandler}
import play.api.mvc.{Handler, RequestHeader}
import scala.reflect.ClassTag
class MyRequestScopedRequestHandler @Inject()(injector: Injector)
extends RequestScopedHttpRequestHandler[DefaultHttpRequestHandler](
injector,
modules = Seq(new MyRequestModule)
)
class RequestScopedHttpRequestHandler[T <: HttpRequestHandler] @Inject() (
injector: Injector,
modules: Seq[AbstractModule] = Seq.empty)(
implicit requestHandlerClassTag: ClassTag[T])
extends HttpRequestHandler {
override def handlerForRequest(request: RequestHeader): (RequestHeader, Handler) = {
val requestScopedModules = new RequestScopedModule(request) +: modules
val childInjector = injector
.createChildInjector(requestScopedModules: _*)
val requestHandler = childInjector
.getInstance(requestHandlerClassTag.runtimeClass)
.asInstanceOf[T]
requestHandler.handlerForRequest(request)
}
}
// RequestScopedModule.scala
import com.google.inject.AbstractModule
import play.api.mvc.RequestHeader
class RequestScopedModule(request: RequestHeader) extends AbstractModule {
override def configure(): Unit = {
bind(classOf[RequestHeader])
.toInstance(request)
bind(classOf[play.mvc.Http.RequestHeader])
.toInstance(new play.core.j.RequestHeaderImpl(request))
}
}
play.api.http.HttpErrorHandlerExceptions$$anon$1: Execution exception[[ProvisionException: Unable to provision, see the following errors:
1) Unable to create binding for com.alexitc.PlayRequestId. It was already configured on one or more child injectors or private modules
bound at com.alexitc.MyRequestModule.configure(MyModules.scala:28)
If it was in a PrivateModule, did you forget to expose the binding?
while locating com.alexitc.PlayRequestId
for the 1st parameter of controllers.MyService.<init>(HomeController.scala:41)
while locating controllers.MyService
for the 2nd parameter of controllers.HomeController.<init>(HomeController.scala:18)
while locating controllers.HomeController
for the 2nd parameter of router.Routes.<init>(Routes.scala:30)
while locating router.Routes
while locating play.api.inject.RoutesProvider
while locating play.api.routing.Router
for the 1st parameter of play.api.http.DefaultHttpRequestHandler.<init>(HttpRequestHandler.scala:91)
while locating play.api.http.DefaultHttpRequestHandler
1 error]]
at play.api.http.HttpErrorHandlerExceptions$.throwableToUsefulException(HttpErrorHandler.scala:255)
at play.api.http.DefaultHttpErrorHandler.onServerError(HttpErrorHandler.scala:182)
at play.api.http.DefaultHttpErrorHandler$.onServerError(HttpErrorHandler.scala:286)
at play.core.server.Server.logExceptionAndGetResult$1(Server.scala:52)
at play.core.server.Server.getHandlerFor(Server.scala:82)
at play.core.server.Server.getHandlerFor$(Server.scala:48)
at play.core.server.AkkaHttpServer.getHandlerFor(AkkaHttpServer.scala:41)
at play.core.server.AkkaHttpServer.getHandler(AkkaHttpServer.scala:214)
at play.core.server.AkkaHttpServer.handleRequest(AkkaHttpServer.scala:194)
at play.core.server.AkkaHttpServer.$anonfun$createServerBinding$3(AkkaHttpServer.scala:106)
Caused by: com.google.inject.ProvisionException: Unable to provision, see the following errors:
1) Unable to create binding for com.alexitc.PlayRequestId. It was already configured on one or more child injectors or private modules
bound at com.alexitc.MyRequestModule.configure(MyModules.scala:28)
If it was in a PrivateModule, did you forget to expose the binding?
while locating com.alexitc.PlayRequestId
for the 1st parameter of controllers.MyService.<init>(HomeController.scala:41)
while locating controllers.MyService
for the 2nd parameter of controllers.HomeController.<init>(HomeController.scala:18)
while locating controllers.HomeController
for the 2nd parameter of router.Routes.<init>(Routes.scala:30)
while locating router.Routes
while locating play.api.inject.RoutesProvider
while locating play.api.routing.Router
for the 1st parameter of play.api.http.DefaultHttpRequestHandler.<init>(HttpRequestHandler.scala:91)
while locating play.api.http.DefaultHttpRequestHandler
1 error
at com.google.inject.internal.InjectorImpl$2.get(InjectorImpl.java:1028)
at com.google.inject.internal.InjectorImpl.getInstance(InjectorImpl.java:1054)
at com.alexitc.RequestScopedHttpRequestHandler.handlerForRequest(MyRequestHandler.scala:30)
at play.core.server.Server.getHandlerFor(Server.scala:69)
at play.core.server.Server.getHandlerFor$(Server.scala:48)
at play.core.server.AkkaHttpServer.getHandlerFor(AkkaHttpServer.scala:41)
at play.core.server.AkkaHttpServer.getHandler(AkkaHttpServer.scala:214)
at play.core.server.AkkaHttpServer.handleRequest(AkkaHttpServer.scala:194)
at play.core.server.AkkaHttpServer.$anonfun$createServerBinding$3(AkkaHttpServer.scala:106)
at akka.stream.impl.fusing.MapAsync$$anon$23.onPush(Ops.scala:1172)
To view this discussion on the web visit https://groups.google.com/d/msgid/play-framework/040b7846-3d35-4530-8a07-f3fa6f050d10%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
To unsubscribe from this group and stop receiving emails from it, send an email to play-framework+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/play-framework/b5758469-c7a0-45a1-8727-7cb8b2c35a91%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
By DefaultHttpRequestHandler is not in the parent injector, it would be a Just In Time binding (jit), guice seems to try to create them as up as possible, surprisingly, I expected that binding DefaultHttpRequestHandler in my request scoped module would lead it to work but it didn't, I'll keep playing this weekend.
Thanks.
--
You received this message because you are subscribed to the Google Groups "Play Framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email to play-framework+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/play-framework/2375aa73-3ceb-4d8e-8133-b3987082d14d%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
With JIT bindings Guice tries to create it in the parentmost injector. You'll have to explicitly bind in the child injector.
On Fri, Sep 8, 2017 at 4:05 PM, Alexis Hernandez <alexi...@gmail.com> wrote:
By DefaultHttpRequestHandler is not in the parent injector, it would be a Just In Time binding (jit), guice seems to try to create them as up as possible, surprisingly, I expected that binding DefaultHttpRequestHandler in my request scoped module would lead it to work but it didn't, I'll keep playing this weekend.
Thanks.
--
You received this message because you are subscribed to the Google Groups "Play Framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email to play-framewor...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/play-framework/2375aa73-3ceb-4d8e-8133-b3987082d14d%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
In fact, I think the issue is that Play needs a binding to the Router to startup properly. This means that we cannot override this Router in child injectors.
I think that the ideal scenario would be to mark 'play.http.router' as 'provided' in 'application.conf' file and bind it in a request scoped module, the issue with this is that Play will look for the binding at startup time instead of when the first request is received.
At this time I can not find a way to get this working without modifying Play source code.
Thanks for all your help Greg.
El viernes, 8 de septiembre de 2017, 19:00:04 (UTC-5), Greg Methvin escribió:With JIT bindings Guice tries to create it in the parentmost injector. You'll have to explicitly bind in the child injector.On Fri, Sep 8, 2017 at 4:05 PM, Alexis Hernandez <alexi...@gmail.com> wrote:By DefaultHttpRequestHandler is not in the parent injector, it would be a Just In Time binding (jit), guice seems to try to create them as up as possible, surprisingly, I expected that binding DefaultHttpRequestHandler in my request scoped module would lead it to work but it didn't, I'll keep playing this weekend.--
Thanks.
You received this message because you are subscribed to the Google Groups "Play Framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email to play-framewor...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/play-framework/2375aa73-3ceb-4d8e-8133-b3987082d14d%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
--
--
You received this message because you are subscribed to the Google Groups "Play Framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email to play-framework+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/play-framework/830d6020-d185-44ba-9951-ca341dcf16e8%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
To view this discussion on the web visit https://groups.google.com/d/msgid/play-framework/830d6020-d185-44ba-9951-ca341dcf16e8%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
--