Retrieving the injector instance in a Play 2.8 application

Hi everyone,

I am migrating a Play Application from 2.4 to 2.8. I have been successful adapting the application and it runs to some degree, but I am currently stuck with a call to the injector.

The current code reads:

private final TestDB testdb = play.api.Play.current().injector().instanceOf(TestDB.class);

which was the recommended way to go in earlier versions of Play. However, play.Play and play.api.Play have been deprecated since version 2.5: Migration25 - 2.8.x

The next option would be using the guice DI as the migration guide explains by using @Inject, which was already used and working in most of the application. However, from what I understand “Injection from a custom class, which is not injected by itself, should be done by explicit call to the injector” (Code Preference: Dependency injection with Guice in Play) and if I try, then indeed the dependencies are not injected and null is given for those variables. So, if I understand correctly, @Inject is not an option since the class is instanciated outside of the injection mechanisms (in accordance to what I see in the code, it uses “new”)

Since it was mentioned on forums, I tried:

@Inject private play.api.inject.Injector injector;
private final TestDB testdb = injector.instanceOf(TestDB.class);

which obviously doesn’t work either, since nothing gets injected, including the Injector.

A parent instance (x calls up) does inject these dependences and as a solution I could pass them along, but I feel there must be a more elegant solution to this. So my actual question is: Is there a way in Play 2.8 to retrieve the injector instance that is used by the application?

Maybe I am missing something very simple, I am rather new to Play and Guice DI, so any help would be greatly appreciated. All the solutions that I found online refer to older versions of play, which do allow direct access to the injector or application objects. The examples from play 2.8 also show how to retrieve the injector, but only in the context of (unit) testing. Also, it is written primarily in Java, rather than Scala.

Best,
Max

If the class is instantiated outside of the injection mechanisms, then @Inject won’t work no matter where you put it. Unless you switch the class to use proper dependency injection, you’ll need to manually pass in an instance of Injector to the constructor.

Hi,

I see, thank you for the advice and for confirming that indeed @Inject is not an option since the class is instanciated outside of the injection mechanisms. Which makes sense, as the previous developers used:

final TestDB testdb = play.api.Play.current().injector().instanceOf(TestDB.class);

So how would I manually pass in an instance of Injector to the constructor? By using

@Inject private play.api.inject.Injector injector;

in the “parent” class and passing that instance on to the constructor?

Wouldn’t that boil down to the less elegant solution I already mentioned of passing instances down over classes? And doesn’t it make sense then to pass down the instance of the class that I want to inject in the first place?

Is there is no other way to get the injector instance directly, like in Play <= 2.4?

There’s kind of a hacky workaround.

First you setup this simple class that holds a static Injector:

public class StaticInjectorHolder {

	public static Injector injector;

}

And then you create a “setter” class for the sole purpose of setting the static injector:

public class StaticInjectorSetter {

	@Inject
	StaticInjectorSetter(Injector injector) {
		StaticInjectorHolder.injector = injector;
	}

}

And then you create a Guice module to specifically inject the setter class eagerly:

public class SetStaticInjectorModule extends AbstractModule {

	@Override
	protected void configure() {
		bind(StaticInjectorSetter.class).asEagerSingleton();
	}

}

And you’ll need to register that module with Play by adding this in application.conf:

play.modules.enabled += "com.example.SetStaticInjectorModule"

And voila, you have access to a static Injector :see_no_evil:. Just make sure you don’t access that static Injector before the binding happens.

1 Like

Wow, I tried the code and it works!
Thanks!, despite it being a workaround, it helps me greatly