Jack Tattersall Jack Tattersall - 11 months ago 96
Scala Question

Scala Play Guice using injector to manually inject a singleton class that has configuration injected into its constructor

using play 2.5 and guice i have managed to successfully inject applicationConfig into a singleton class and reference a config variable inside it,

trait TMongoFactory{
val SERVER: String
val PORT: Int
val DATABASE: String
val connection: MongoClient
val collection: MongoDB

class MongoFactory @Inject()(val configuration: Configuration) extends TMongoFactory{
val SERVER = "localhost"
val PORT = 27017
val DATABASE = configuration.underlying.getString("connectionString")
val connection = MongoClient(SERVER, PORT)
val collection = connection(DATABASE)

class MongoModule extends AbstractModule {
def configure() = {

I can then pass this singleton to a repository class like so

class MongoRemainingAllowanceRepository @Inject()(MongoFactory: TMongoFactory) extends RemainingAllowanceRepository{
val context = MongoFactory.collection("remainingAllowance")
def save(remainingAllowance: RemainingAllowance): Unit ={

This all works fine and as expected, but the problem is i need to call this repository in the test suite so i dont want it to have to take any arguments (specifically injected ones).
So i tried to change it to use an injector inside the body like so

class MongoRemainingAllowanceRepository extends RemainingAllowanceRepository{
val injector = Guice.createInjector(new MongoModule)
val mongoFactory = injector.getInstance(classOf[TMongoFactory])

val context = mongoFactory.collection("remainingAllowance")
def save(remainingAllowance: RemainingAllowance): Unit ={

This feels like it should work and it compiles fine, but then on test or run it throws an error

Could not find a suitable constructor in play.api.Configuration. Classes
must have either one (and only one) constructor annotated with @Inject
or a zero-argument constructor that is not private. at
play.api.Configuration.class(Configuration.scala:173) while locating

Apologies for the long post but i feel i needed to include most of this.
Does anyone know why this happens on an injector? Do i need to bind the configuration manually also now im referencing the custom module?

Any help appreciated

Answer Source

When you create your class you can pass in the configuration yourself. Say you need key apiKey and its value...

val sampleConfig = Map("apiKey" ->"abcd1234")
val mongoFactory = new MongoFactory(Configuration.from(sampleConfig))