--
You received this message because you are subscribed to the Google Groups "Play framework dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to play-framework-...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
As long as we have play.api.Play.current, we can not have
constructor-based DI. I don’t really see how you can expect to give a
preview of what DI will look like in Play 3.0 if we still have a
global state in 2.4.
Also, constructor-based DI is the simplest solution, probably my
favorite, but does not work anymore if you have recursive
dependencies. The cake can handle that, though it is more complex to
harness… Anyway, let’s try if we can provide an acceptable solution
with constructor-based dependencies.
I think that plugins themselves should be as minimal as possible, and should basically only be concerned with integrating a particular module's behavior with the Play application, but I think they need to be injectable because the components they're providing might have their own dependencies.
I think having a binding API might be unnecessarily complex for most cases. The simplest way for a plugin to provide dependencies is exactly to how we do it with DBPlugin and CachePlugin using pure Scala: you provide methods on the plugin which return the instances. Then a user can bind those directly, for example in a Guice module, if desired. Most plugins external to your application should be fairly self-contained, and within your application you'll probably want to use your preferred DI solution.
The more generic approach I was proposing integrates a bit less nicely with runtime DI, but it's also less opinionated, and actually makes it reasonable to use compile-time DI as well. If, for example, you're using implicits or cake pattern, all you should need to do is construct a list of controllers and plugins, and the global, which is all Play needs to know about.
I think you have some good points but there are a few concerns I have about your proposal that I'm not clear on:First is that I want Play to integrate as seamlessly as possible with any DI interface. If you use Guice in your application, you should be able to use Guice modules just as easily as you would any other interface. Why would I want to use Plugins if I could use regular Guice modules? Or is this just for third-party plugins to integrate with Play?
Second is that I'd prefer not to redefine what a Plugin is. As far as I'm concerned, Plugin is an interface that lets you define what happens when the application starts and stops. I think there is also confusion with sbt plugins vs Play plugins (which are both used in Play projects), so having plugins do something different in 2.4 is likely to create more confusion.
It also happens that you can call app.plugin[PluginClass] to "inject" a plugin as a dependency. The fact that this was being used by third-party plugins was the original motivation for having plugins themselves be instantiable via DI, so you could easily create custom implementations of interfaces that the main plugin (e.g. SecureSocial) depended on. I don't think this is an ideal method of doing DI, but it does provide a way for third-party modules to have customizable dependencies. How would this work with the new system you're talking about?
It's not just that, it also gives you a way to access shared resources - it is a provider of components. The most ugly part of the plugin trait I think is actually the start/stop side of things - it depends on arbitrarily chosen numbers for ordering in the config file. While this will still work in Play 2.4, it's something that we want to move away from. I suspect in Play 2.4, none of the built in plugins will actually provide an implementation of start/stop, Play will still invoke start/stop at the appropriate times, but only for backwards compatibility. In Play 3.0 we can completely remove them.
On Wed, Jun 18, 2014 at 8:14 AM, Greg Methvin <greg.m...@gmail.com> wrote:
>
> Okay, so it seems like the idea is to provide a generic API for integrating any DI framework, in addition to a way to define "modules" for the framework which bind other dependencies. Ideally this would be a two-way integration, so a dependency bound by a Play module would be accessible in Guice/Spring/Subcut/etc., and vice versa.
Yes.
> How sophisticated do you guys think this binding framework needs to be? I'd prefer to keep it fairly minimal. We could also choose some existing DI implementation and go with that as the default, but depending on what we use it could be tricky to provide a convenient API for integrating with users' own DI tools.
Completely agree, it should be minimal. I would say we need to provide the following feature set, and no more:
* bind implementation class to interface
* bind Provider to interface
* bind instance to interface
* named bindings
* eager singletons (this may or may not be achieved using the DI framework)
Things that I think we should specifically leave out of scope:
* scoped bindings - this doesn't really fit with Play's way doing things
* parameterised type bindings - if you want to dependency inject a list of things for example, it's really not hard to just wrap it in another type
A few other things that I've been thinking about as a result of a few discussions at ScalaDays:
* config: should we inject a config object and use that, or should we inject each config item with a named binding? I'm tending toward the first, since that means we can add new config without changing the constructor (and public api)
* Scala: I'm thinking more and more that we should provide out of the box support for either macwire or subcut. This would mean we provide traits for mixing in the default play components. With macwire, I don't think we even need to have a dependency on it, if we just provide traits with manually wired core modules as lazy vals, then it will be very easy with very minimal effort for an end user to use macwire. I need to check out subcut to see how it would fit into play.
--
James Roper
Software Engineer
Typesafe – Build reactive apps!
Twitter: @jroper
SEE YOU IN BERLIN
Scala
Days
June 16th-18th,
Berlin
On Jun 18, 2014 10:44 AM, "James Roper" <ja...@typesafe.com> wrote:
>
>
> On Wed, Jun 18, 2014 at 8:14 AM, Greg Methvin <greg.m...@gmail.com> wrote:
> >
> > Okay, so it seems like the idea is to provide a generic API for integrating any DI framework, in addition to a way to define "modules" for the framework which bind other dependencies. Ideally this would be a two-way integration, so a dependency bound by a Play module would be accessible in Guice/Spring/Subcut/etc., and vice versa.
>
> Yes.
>
> > How sophisticated do you guys think this binding framework needs to be? I'd prefer to keep it fairly minimal. We could also choose some existing DI implementation and go with that as the default, but depending on what we use it could be tricky to provide a convenient API for integrating with users' own DI tools.
>
> Completely agree, it should be minimal. I would say we need to provide the following feature set, and no more:
>
> * bind implementation class to interface
> * bind Provider to interface
> * bind instance to interface
> * named bindings
> * eager singletons (this may or may not be achieved using the DI framework)
>
> Things that I think we should specifically leave out of scope:
>
> * scoped bindings - this doesn't really fit with Play's way doing things
> * parameterised type bindings - if you want to dependency inject a list of things for example, it's really not hard to just wrap it in another type
>
> A few other things that I've been thinking about as a result of a few discussions at ScalaDays:
>
> * config: should we inject a config object and use that, or should we inject each config item with a named binding? I'm tending toward the first, since that means we can add new config without changing the constructor (and public api)
> * Scala: I'm thinking more and more that we should provide out of the box support for either macwire or subcut. This would mean we provide traits for mixing in the default play components. With macwire, I don't think we even need to have a dependency on it, if we just provide traits with manually wired core modules as lazy vals, then it will be very easy with very minimal effort for an end user to use macwire. I need to check out subcut to see how it would fit into play.
I can recommend you to have a look at scaldi as well. It already integrates with play and has a good implementation of modules IMO.
>
> --
> James Roper
> Software Engineer
>
> Typesafe – Build reactive apps!
> Twitter: @jroper
>
> SEE YOU IN BERLIN
> Scala
> Days
> June 16th-18th,
> Berlin
>
> On 18 Jun 2014 08:15, "Greg Methvin" <greg.m...@gmail.com> wrote:
>>
>> Okay, so it seems like the idea is to provide a generic API for integrating any DI framework, in addition to a way to define "modules" for the framework which bind other dependencies. Ideally this would be a two-way integration, so a dependency bound by a Play module would be accessible in Guice/Spring/Subcut/etc., and vice versa.
>>
>> How sophisticated do you guys think this binding framework needs to be? I'd prefer to keep it fairly minimal. We could also choose some existing DI implementation and go with that as the default, but depending on what we use it could be tricky to provide a convenient API for integrating with users' own DI tools.
>
Am 18.06.2014 12:59 schrieb "Yann Simon" <yann.s...@gmail.com>:
>
> I can recommend you to have a look at scaldi as well. It already integrates with play and has a good implementation of modules IMO.
>
> http://scaldi.org
Here's a (biased) comparison of subcut and scaldi: http://stackoverflow.com/a/16660055/130167
If play wouldn't come with scaldi support out of the box it would be great if we could contribute this so that it will be shipped with play then.
Cheers,
Martin
My hope is that whatever approach we take will allow third party libraries to provide support for other DI frameworks seamlessly and idiomatically. The plan for developing this is that we will release Play 2.4-M1 very early, as soon as we have exposed public constructors to internal components and have basic guice support, and at that time it would be awesome if people could start trying to integrate that with other DI frameworks, so that we can validate or modify the approach if necessary.
>
> Cheers,
> Martin
Sounds good!
Cheers,
Martin
Completely agree, it should be minimal. I would say we need to provide the following feature set, and no more:
* bind implementation class to interface
* bind Provider to interface
* bind instance to interface
* named bindings
* eager singletons (this may or may not be achieved using the DI framework)Things that I think we should specifically leave out of scope:
* scoped bindings - this doesn't really fit with Play's way doing things
* parameterised type bindings - if you want to dependency inject a list of things for example, it's really not hard to just wrap it in another type
A few other things that I've been thinking about as a result of a few discussions at ScalaDays:
* config: should we inject a config object and use that, or should we inject each config item with a named binding? I'm tending toward the first, since that means we can add new config without changing the constructor (and public api)
* Scala: I'm thinking more and more that we should provide out of the box support for either macwire or subcut. This would mean we provide traits for mixing in the default play components. With macwire, I don't think we even need to have a dependency on it, if we just provide traits with manually wired core modules as lazy vals, then it will be very easy with very minimal effort for an end user to use macwire. I need to check out subcut to see how it would fit into play.
* bind implementation class to interface
* bind Provider to interface
* bind instance to interface
* named bindings
* eager singletons (this may or may not be achieved using the DI framework)
I'd like to remove the idea of an explicit "mode" value in 3.0 and just rely on DI to inject different configuration when we start the application in prod, dev and testing.
Are you talking about these two approaches to config?1. class MyClass(config: com.typesafe.config.Config)2. class MyClass(setting1: @Named("Setting1") String)
There's also this approach:3. class MyClass(config: MyConfig)
* bind implementation class to interface
* bind Provider to interface
* bind instance to interface
* named bindings
* eager singletons (this may or may not be achieved using the DI framework)We might be able to get away without having named bindings by always injecting custom types. I've never found named bindings that useful, but that could be because it's easier to create wrapper classes or "config" case classes in Scala.
I'd like to remove the idea of an explicit "mode" value in 3.0 and just rely on DI to inject different configuration when we start the application in prod, dev and testing.Agreed. Any internal logic that depends on the mode, or any global parameter from the application, is a bad idea, and will just make your components less testable.
Are you talking about these two approaches to config?1. class MyClass(config: com.typesafe.config.Config)2. class MyClass(setting1: @Named("Setting1") String)
There's also this approach:3. class MyClass(config: MyConfig)I tend to use option 3 a lot in my own code, especially when I have configuration mixed with other dependencies.
Another thing that works is to define a Provider which constructs it, like this:@Provides def myClass(conf: Configuration): MyClass =new MyClass(setting1 = conf.getString("setting1"), setting2 = conf.getString("setting2"))
For the compile-time frameworks, the easiest thing would be for Play to provide a trait with lazy vals or defs for all the dependencies the framework can provide (e.g. configuration, WSClient, etc.), then you can just directly access those methods.
I don't see a clear distinction here. At some point there has to be some logic looking at the mode and making a different decision based on it. Consider error page rendering, we could create a default error page abstraction, with one implementation that renders detailed exceptions/source code in dev mode, and one implementation that renders a minimal error message - but I just don't see what we're gaining there over a switch, all I see is additional complexity - there is now a new abstraction (and therefore public API) for default error reporting, and there's more complex setup wiring code to ensure the right things happen.
--
On Tue, Jun 3, 2014 at 5:39 PM, Julien Richard-Foy <j...@zengularity.com> wrote:
As long as we have play.api.Play.current, we can not have
constructor-based DI. I don’t really see how you can expect to give a
preview of what DI will look like in Play 3.0 if we still have a
global state in 2.4.Why not? Today you use WS by doing this:WS.url(...)And that depends on the global state. In Play 2.4, you will be able to:class MyController(wsClient: WSClient) {wsClient.url(...)}And that won't use global state, so you can test MyController in isolation. You will still be able to use WS.url(...), but we will encourage the latter. My hope is that in Play 2.4 all plugins will be accessible both through the current static mechanism, as well as through DI.
We will be making an injectable router... Generating a router that declares its dependencies in a constructor. So a fully compile time injected application will be possible. And we hope to get rid of all dependence on Play.current internally, if not get rid of it altogether, in 3.0.
We will be making an injectable router...
We also need the ApplicationProvider thing that you described in the other thread
ApplicationLoader/Provider/Begetter/Whatever will definitely be in 2.4. A new router... Depends whether we have time or not. I think we could make it configurable (ie you choose which router implementation), so both can be generated.
Actually, if we complete the example we see that we *must* use runtime DI even though our controller class takes its dependencies in its constructor.Indeed, if you want to use compile-time DI for your controller, it has to be defined as a static value, at some point (this is true only with the current design of the router). Maybe one could believe that he can define an object MyController like this:// Easy to test!class MyController(wsClient: WSClient) {…}// Finally, for the routerobject MyController extends MyController(WS.client(play.api.Play.current))But the above simply does not work because play.api.Play.current is *not* a stable reference due to the hot reloading mechanism. It means that if your application is reloaded, the MyController object still refers to the old application.
Actually, this is a constellation I am using, and it works.
Actually, this is a constellation I am using, and it works.Is a new controller object created each time you perform a request? How does your DI mechanism know that a controller is dirty (due to an application reload) and must be recreated?
Damn phone my answer went to julien alone.
> I am pretty sure all application code is loaded in a specific classloader.
>
> When a file is changed leading to an app restart in Dev mode, the whole class loader gets discarded including any object instances it might have held.
> This in turn forces a reinit of everything and thus the the references are correct
>
> When testing however one doesn't use the object, but instanciates the class directly instead, giving a mock/stub/dummy for the dependency or even a concrete implem referencing the fake application in scope.
>
> I use a variation of this with traits having abstract members which are actually implemented in the object or in a class for tests. The constructor solution is cleaner but we lacked time to refactor.
>
> Jean
>
> Le 4 juil. 2014 11:23, "Julien Richard-Foy" <j...@zengularity.com> a écrit :
>
>>> Actually, this is a constellation I am using, and it works.
>>
>>
>> Is a new controller object created each time you perform a request? How does your DI mechanism know that a controller is dirty (due to an application reload) and must be recreated?
>>
Said otherwise, my question is: how does the DI system know that it can reuse the same previous instance instead of re-creating one, when we call its getInstance method?
--On Fri, Jul 4, 2014 at 12:05 PM, Yann Simon <yann.s...@gmail.com> wrote:
2014-07-04 11:23 GMT+02:00 Julien Richard-Foy <j...@zengularity.com>:
Actually, this is a constellation I am using, and it works.Is a new controller object created each time you perform a request? How does your DI mechanism know that a controller is dirty (due to an application reload) and must be recreated?The new controller object should be created after each application reload.I think that, as the class loader with the old instances is removed, the new class loader does not know this controller yet and instantiates a new one.I'll check that.Z E N G U L A R I T Y
–––––––––––––––––––––––Julien RICHARD-FOY - Programmer56 rue Saint Lazare 75009 Paris625 Market Street - San Francisco
--
You received this message because you are subscribed to the Google Groups "Play framework dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to play-framework-...@googlegroups.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 dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to play-framework-...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
James,
Just a quick question. I can understand how I can define multiple applications wired using different dependencies. But how am I going to specify which application to be loaded? For example one for development, one for production and one for test…
The DI system will have its lifecycle bound to the Application - when a new Application is created, a new DI container will be created.
In your experience (and anyone elses) what would be the best approach here? I'm tending towards the first approach, it is very lightweight, and completely optional - if the trait didn't quite do what you need to do, you can always fallback to just using plain constructors, which a framework like macwire would make a lot easier for you too.Thoughts?
— I needed to add a resolver to get sbt correctly resolve a scalaz dependency ;
— In application.conf, while you can write:play.modules.enabled += "some.Module"or:but you can not write:play.modules.enabled += ["some.Module", "some.OtherModule"](this is more a HOCON concern than a Play concern) ;
— The supported configuration is still inconsistent between some components. For instance the jdbc component still uses the “db” key prefix and the application’s secret key still uses the “application.secret” key while the evolutions component uses the “play.modules.evolutions” key prefix. I think we should always use keys under the “play” prefix (so, in the examples above we should use “play.modules.jdbc” instead of “db”, and “play.application.secret” instead of “application.secret”). I’m not sure we should keep the “modules” subkey: why not use “play.evolutions” and “play.i18n” instead of “play.modules.evolutions” and “play.modules.i18n”, respectively?
— The conversion to the new way of achieving DI was straightforward (I just had to define injectable constructors for my modules and, if needed, define their bindings) and internal Play things worked well. However, I got some troubles when I wanted to customize the wiring in tests. For instance, I couldn’t find a way to add a binding to a mock that is still in the scope of my test code (so that I can control the behavior of this mock). Here is what I did with 2.3 (where GuiceInjector is a GlobalSetting subclass that sets up a Guice injector). The 2.4 version I wrote does not work: I get a NullPointerException here. This is definitely a use case we should straightforwardly support ;
— More generally, the WithApplicationLoader scope (that I wrote) is of very little help because we can not pass it custom configuration settings. It is very common to load some common modules in both test and run modes but to customize the behaviour of some module via the configuration (typically, the database URL for the jdbc module). WithApplicationLoader allows us to set which ApplicationLoader to use and eventually to define custom bindings, but it does not help to define custom configuration settings. To workaround this limitation I used WithApplication instead of WithApplicationLoader everywhere I could, and used its additionalConfiguration parameter to define my custom configuration.
— Then I upgraded the code base to use compile-time dependency injection. Contrary to runtime DI, the experience with compile-time DI was tougher because there is almost no documentation (for each module we should document how it is intended to be used with a compile-time DI approach, e.g. for the evolutions module we should tell users that at some point they have to explicitly evaluate the applicationEvolutions lazy val)
and, above all, because Play internals still rely on runtime DI at some places:
— The HTML helpers internally use the i18n API based on runtime DI (in that case I think we could fix this by passing them an implicit Messages instead of an implicit Lang) ;
— The “request2Lang” member of Controller does the same ;— The “route” member of the test helpers delegates to the application’s “global” member to retrieve the handler for a given request, and this “global” member is itself initialized using the runtime dependency injector. I think the first problem could be solved by using the application’s “requestHandler” member instead of “global”, like I did here. The second problem (the initialization of the “global” member of Application) seems harder to solve.
— More generally, it was difficult, for a given module, to know if it relies on a runtime injector or not. For instance, the jdbc module provides a “DB” object whose methods all have an implicit parameter of type Application so that the actual DBApi to use can be retrieved using the application’s injector. The same applies to the i18n module and its “Messages” object. Maybe this kind of APIs should be deprecated so that users always retrieve the DBApi or the MessagesApi in their module dependencies instead of using this level of indirection via the application’s injector, but, more importantly, I think that code using these APIs should not compile when you don’t use a runtime injector. In the same vein, I think that Application should not have an “injector” member.
— It was not straightforward to use the i18n module. First, I had to define an implicit conversion from RequestHeader to Messages in my controllers, and then at usage site I had to write this inconvenient syntax. I think that a solution to this problem could be to make the Messages object take an implicit Messages parameter instead of Lang (so we could use the same syntax as in 2.3 to get i18n, provided we have such an implicit conversion from RequestHeader to Messages).
— It looks weird that we set which ApplicationLoader to use in the application.conf file. This is especially a non-sense when we use a FakeApplication, which is definitely not leaded via our custom ApplicationLoader but still uses it to load some modules (excepted the FakeApplication itself, obviously).
— This point is maybe related to the previous one, it may happen that one wants to reuse a component of Play without having to rely on the whole ApplicationLoader machinery. For instance, to reuse the evolutions component in my tests I can write a trait defining how to wire the components of my service and then use it to create my service in my tests. It turns out that in that case I don’t need an application (nor a router), I just need an Environment or a Configuration. That’s why I created a WithContext specs2 scope that creates a Context (which contains an environment and a configuration) and that supports the definition of custom configuration settings, unlike WithApplicationLoader.
— BTW I think that the member “initialConfiguration” of Context should be named just “configuration”.
— I was happy to use WithApplicationLoader to run my tests using my custom application loader, but only after I wrote a method to modify the configuration settings.— It was not possible to directly use WithBrowser because it takes a FakeApplication as parameter, though I was only able to produce an Application with my ApplicationLoader. I copy-pasted it and just changed its signature so that it takes an Application instead of a FakeApplication and it worked well. I hope we can apply the same change in Play.
— Note that I was still unable to wire a dependency to a mock while keeping a reference to it in the scope of my tests. Here, my workaround was to write my tests using just my controller instead of a running application but I think we should also support testing using a running application.
— I had troubles using the injected router because by default routers are generated in the empty package which you can not refer to unless you are in the empty package too. My workaround was to make my routers always use subpackages.
— I had to add this line to get the evolutions component working. I think the dynamicEvolution member should not be abstract in the EvolutionsComponents, am I correct?
That’s all for today!
Cheers,Julien
Yeah, this is very hard to get away from until we've completely eradicated the global state - the current solution we have for this is to provide a simple injector that provides the compile time injected components that are currently needed - it seems like there may be a few extra components that we need to make available via this mechanism.
— The “request2Lang” member of Controller does the same ;— The “route” member of the test helpers delegates to the application’s “global” member to retrieve the handler for a given request, and this “global” member is itself initialized using the runtime dependency injector. I think the first problem could be solved by using the application’s “requestHandler” member instead of “global”, like I did here. The second problem (the initialization of the “global” member of Application) seems harder to solve.Yes, the fix for the first problem is quite straight forward.
— It was not straightforward to use the i18n module. First, I had to define an implicit conversion from RequestHeader to Messages in my controllers, and then at usage site I had to write this inconvenient syntax. I think that a solution to this problem could be to make the Messages object take an implicit Messages parameter instead of Lang (so we could use the same syntax as in 2.3 to get i18n, provided we have such an implicit conversion from RequestHeader to Messages).This is good to know, we'll have to come up with a way to generically solve this.
— This point is maybe related to the previous one, it may happen that one wants to reuse a component of Play without having to rely on the whole ApplicationLoader machinery. For instance, to reuse the evolutions component in my tests I can write a trait defining how to wire the components of my service and then use it to create my service in my tests. It turns out that in that case I don’t need an application (nor a router), I just need an Environment or a Configuration. That’s why I created a WithContext specs2 scope that creates a Context (which contains an environment and a configuration) and that supports the definition of custom configuration settings, unlike WithApplicationLoader.Here's an example of what I've done to implement testing using evolutions/database without instantiating a whole application:At the bottom of that spec is number of helpers, these I've already started generalising and pulling into Play.
— It was not possible to directly use WithBrowser because it takes a FakeApplication as parameter, though I was only able to produce an Application with my ApplicationLoader. I copy-pasted it and just changed its signature so that it takes an Application instead of a FakeApplication and it worked well. I hope we can apply the same change in Play.Definitely.
— I had troubles using the injected router because by default routers are generated in the empty package which you can not refer to unless you are in the empty package too. My workaround was to make my routers always use subpackages._root_ doesn't work?
Yeah, this is very hard to get away from until we've completely eradicated the global state - the current solution we have for this is to provide a simple injector that provides the compile time injected components that are currently needed - it seems like there may be a few extra components that we need to make available via this mechanism.I’m not sure to see what you mean by this “inject that provides compile time injected components”. Can you point me to the code?
— The “request2Lang” member of Controller does the same ;— The “route” member of the test helpers delegates to the application’s “global” member to retrieve the handler for a given request, and this “global” member is itself initialized using the runtime dependency injector. I think the first problem could be solved by using the application’s “requestHandler” member instead of “global”, like I did here. The second problem (the initialization of the “global” member of Application) seems harder to solve.Yes, the fix for the first problem is quite straight forward.PR sent here: https://github.com/playframework/playframework/pull/3774— It was not straightforward to use the i18n module. First, I had to define an implicit conversion from RequestHeader to Messages in my controllers, and then at usage site I had to write this inconvenient syntax. I think that a solution to this problem could be to make the Messages object take an implicit Messages parameter instead of Lang (so we could use the same syntax as in 2.3 to get i18n, provided we have such an implicit conversion from RequestHeader to Messages).This is good to know, we'll have to come up with a way to generically solve this.We could provide the following trait:trait MessagesSupport {def messagesApi: MessagesApiimplicit def request2Messages(implicit rh: RequestHeader): Messages = messagesApi.preferred(rh)}So that users just have to mix it in their controllers. In my example I would just have to write the following:class Authentication(users: Users, val messagesApi: MessagesApi) extends Controller with MessagesSupport {}This would work for runtime DI users as well (they just need to make their class injectable).We could also provide a way to get an easy update solution for users that are still using the static API by defining an implicit conversion that also takes an implicit Application as parameter:implicit def request2Messages(implicit rh: RequestHeader, app: Application): Messages =app.injector.instanceOf[MessagesApi].preferred(rh)I’m not sure whether the Controller trait should by default have these conversions or if they should explicitly be mixed in by users.
— This point is maybe related to the previous one, it may happen that one wants to reuse a component of Play without having to rely on the whole ApplicationLoader machinery. For instance, to reuse the evolutions component in my tests I can write a trait defining how to wire the components of my service and then use it to create my service in my tests. It turns out that in that case I don’t need an application (nor a router), I just need an Environment or a Configuration. That’s why I created a WithContext specs2 scope that creates a Context (which contains an environment and a configuration) and that supports the definition of custom configuration settings, unlike WithApplicationLoader.Here's an example of what I've done to implement testing using evolutions/database without instantiating a whole application:At the bottom of that spec is number of helpers, these I've already started generalising and pulling into Play.Interesting, thanks for the link.— It was not possible to directly use WithBrowser because it takes a FakeApplication as parameter, though I was only able to produce an Application with my ApplicationLoader. I copy-pasted it and just changed its signature so that it takes an Application instead of a FakeApplication and it worked well. I hope we can apply the same change in Play.Definitely.— I had troubles using the injected router because by default routers are generated in the empty package which you can not refer to unless you are in the empty package too. My workaround was to make my routers always use subpackages._root_ doesn't work?No, the empty package can not be accessed using _root_. See http://stackoverflow.com/a/9822212/561721
Julien
--
You received this message because you are subscribed to the Google Groups "Play framework dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to play-framework-...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
— It was not straightforward to use the i18n module. First, I had to define an implicit conversion from RequestHeader to Messages in my controllers, and then at usage site I had to write this inconvenient syntax. I think that a solution to this problem could be to make the Messages object take an implicit Messages parameter instead of Lang (so we could use the same syntax as in 2.3 to get i18n, provided we have such an implicit conversion from RequestHeader to Messages).This is good to know, we'll have to come up with a way to generically solve this.We could provide the following trait:trait MessagesSupport {def messagesApi: MessagesApiimplicit def request2Messages(implicit rh: RequestHeader): Messages = messagesApi.preferred(rh)}So that users just have to mix it in their controllers. In my example I would just have to write the following:class Authentication(users: Users, val messagesApi: MessagesApi) extends Controller with MessagesSupport {}This would work for runtime DI users as well (they just need to make their class injectable).We could also provide a way to get an easy update solution for users that are still using the static API by defining an implicit conversion that also takes an implicit Application as parameter:implicit def request2Messages(implicit rh: RequestHeader, app: Application): Messages =app.injector.instanceOf[MessagesApi].preferred(rh)I’m not sure whether the Controller trait should by default have these conversions or if they should explicitly be mixed in by users.I like the MessagesSupport trait, I think we should go with that.
— I had troubles using the injected router because by default routers are generated in the empty package which you can not refer to unless you are in the empty package too. My workaround was to make my routers always use subpackages._root_ doesn't work?No, the empty package can not be accessed using _root_. See http://stackoverflow.com/a/9822212/561721Ok. Sounds like we should change the default router to be in a package then. Any idea on what package? controllers might be a good package, but I wonder if that would cause any namespacing conflicts. Maybe routes.Routes? main.Routes?
Hi,Here is some more feedback. I upgraded play-jsmessages to Play 2.4.0 (BTW is there a way to point to the snapshots in my build?). The Scala sample wires everything at compile-time.
I didn’t use an ApplicationLoader in my tests because you can not get anything else than a Application from such a type, though I wanted to also retrieve, for instance, the WSClient for some of my tests. So I ended up with this pattern: I define a trait that extends BuiltInComponents and provides the components of my application. Then I use it in my ApplicationLoader as well as in my tests. In the latter case, I even mix in another components trait.
I think Play should provide a way to get an ApplicationLoader.Context without too much boilerplate.