11

I am a big fan of Dependency Injection and the Play Framework, but am having trouble seeing how the two could be exploited together.

There are modules for Spring and Guice, but the way that Play works makes it hard for me to see how DI could be beneficial beyond some quite simple cases.

A good example of this is that Play expects JPA work to be done by static methods associated with the entity in question:

@Entity
Person extends Model {
    public static void delete(long id) {
        em().find(id).remove();
    }

    //etc
}

So there is no need for a PersonManager to be injected into controllers in the way it might for a Spring J2EE application. Instead a controller just calls Person.delete(x).

Obviously, DI is beneficial when there are interfaces with external systems, as the concrete implementation can be mocked for testing etc., but I don't see much benefit for a self-contained Play application.

Does anyone have any good examples? Does anyone use it to inject a Manager-style class into Controllers so that a number of operations can be done within the same transaction, for example?

ripper234
  • 222,824
  • 274
  • 634
  • 905
Rich
  • 15,602
  • 15
  • 79
  • 126
  • Hi, I edited the title to specify DI _use cases_ - because this question doesn't ask "how to use DI with Play", but rather when. I'm still looking for the how - Guice Module isn't working well for me yet. – ripper234 Nov 21 '11 at 16:28

6 Answers6

5

The problem in my humble opinion on the static initialization approach of Play! is that it makes testing harder. Once you approach the HTTP vs Object Orientation problem with static members and objects that carries the HTTP message data (request and response) you make a trade of having to create new instances for each request by the ability of make your objects loosely coupled with the rest of your project classes.

One good example of a different design are servlets, it also extends a base class but it approaches the problem with a single instance creation (by default, because there are configurations that enable more instances).

I believe that maybe a mix of the two approaches would be better, having a singleton of each controller would give the same characteristics of a full static class and would allow dependency injection of some kinds of object. But not the objects with request or session scope, once the controller would need to be created every new request. Moreover it would improve testability by inverting the control of dependency injection, thus allowing arbitrary injection points.

Dependencies would be injected by the container or by a test, probably using mocks for the heavy stuff that much likely would already have been tested before.

In my point of view, this static model pushes the developer away from testing controllers because extending FunctionalTest starts the application server, thus paying the price of heavy objects like repositories, services, crawlers, http clients, etc. I don't want to wait a lot of objects to be bootstrapped just to check if some code was executed on the controller, tests should be quick and clear to make developers love them as their programming assistant/guide.

Community
  • 1
  • 1
Jayr Motta
  • 718
  • 1
  • 8
  • 26
  • I've been thinking about "But not the objects with request or session scope, once the controller would need to be created every new request.", how could that be accomplished? This could be allowed through some convenient objects that would be set for a given request and these objects would carry request/session data, but if these objects are set in instance variables there is the whole problem of concurrency and synchronization, paying this price would decrease the overall throughput because of the contention. Would it be better to have a controller instance per user? – Jayr Motta Nov 01 '12 at 13:23
5

I believe from this sentence you wrote:

"Does anyone have any good examples? Does anyone use it to inject a Manager-style class into Controllers so that a number of operations can be done within the same transaction, for example?"

that before answering the DI question I should note something: transactions are managed automatically by Play. If you check the model documentation you will see that a transaction is automatically created at the beginning of a request, and committed at the end. You can roll it back via JPA or it will be rolled back if an exception is raised.

I mention this because from the wording of your sentence I'm not sure if you are aware of this.

Now, on DI itself, in my (not-so-extensive) experience with DI, I've seen it used mainly to:

  • Load the ORM (Hibernate) factory/manager
  • Load Service classes/DAOs into another class to work with them

Sure, there are more scenarios, but these probably cover most of the real usage. Now:

  • The first one is irrelevant to Play as you get access to your JPA object and transaction automatically
  • The second one is quite irrelevant too as you mainly work with static methods in controllers. You may have some helper classes that need to be instantiated, and some may even belong to a hierarchy (common interface) so DI would be beneficial. But you could just as well create your won factory class and get rid of the jars of DI.

There is another matter to consider here: I'm not so sure about Guice, but Spring is not only DI, it also provides a lot of extra functionalities which depend on the DI module. So maybe you don't want to use DI in Play, but you want to take advantage of the Spring tools and they will use DI, albeit indirectly (via xml configuration).

Pere Villega
  • 16,429
  • 5
  • 63
  • 100
2

DI is not the ultimate solution to use everywhere... Don't use DI just because you have it in your hands... In play, you don't need DI to develop controllers/models etc... but sometimes it could be a nice design: IMO, you could use it if you have a service with a well know interface but you would like to develop this service outside Play and test it outside play and even test your play project with just a dummy service in order NOT to depend on the full service implementation. Therefore DI can be interesting: you plug the service loosely in play. In fact, this is the original use case for DI afaik...

mandubian
  • 4,427
  • 1
  • 22
  • 15
  • 1
    Don't think that I was going to use DI just because I could. I was trying to see *how* DI could be used in Play. There is obviously a need for DI otherwise the Spring and Guice modules would not have been written, but, as I said in my original question, the way that Play works seems to make using DI difficult, and perhaps unnecessary. – Rich Feb 17 '11 at 12:26
  • I agree with you concerning DI in general... It's just that I see that lots of people tend to use DI everywhere even if it doesn't fit very well. You know it's always like that: we discover something clever and we want to use it everywhere but it's not meant for some particular case :)... hibernate was the same... WebServices also... XML everywhere... and now REST everywhere... JSON etc... Anyway, I think nothing prevents from using Play + DI: Play is just not meant to be stateful but DI neither so... – mandubian Feb 17 '11 at 20:37
2

I just wrote a blog post about setting up a Play Framework application with Google Guice. http://geeks.aretotally.in/dependency-injection-with-play-framework-and-google-guice

I see some benefits, especially when a component of your application requires a different behavior based on a certain context or something like that. But I def believe people should be selective about what goes into a DI context.

Felipe Oliveira
  • 1,041
  • 9
  • 9
1

It shows again that you should only use dependencies injection if you really have a benefit. If you have complex services it's useful, but in many cases it's not. Read the chapter about models in the play-documentation.

So to give you an example where you can use DI with play. Perhaps you must make a complex calculation, or you create a pdf with a report-engine. There I think DI can be useful, specially for testing. There I think the guice-module and spring-module are useful and can help you.

Niels

niels
  • 7,321
  • 2
  • 38
  • 58
0

As of a year and some change later, Play 2.1 now has support for dependency injection in controllers. Here's their demo project using Spring 3, which lays it out pretty clearly.

Edit: here's another example using Guice and Scala, if that's your poison.

Tim Gilbert
  • 5,721
  • 5
  • 33
  • 28