1

I am using wire in my scala project. I have a usecase ---

class SchemaRegistry(registry: SchemaRegistryClient) 

class SchemaRegistryClient(url: String) extends RestService(url) {}

trait EndpointModule  {
  // Schema Registry endpoint dependency
  lazy val schemaRegistry: SchemaRegistry = wire[SchemaRegistry]
  def schemaRegistryClient(url: String): SchemaRegistryClient = wire[SchemaRegistryClient]
}

object LightweightinstructionRunner extends EndpointModule with ConfigModule {
    val client = schemaRegistryClient("")
}

This throws an error -

Cannot find a value of type: [etl.infrastructure.endpoints.SchemaRegistryClient]

It works if I create hardcoded object of SchemaRegistryClient inside the EndpointModule.

(val c = new SchemaRegsitryClient(""))

Can anyone help in explaining how to workaround this and what is happening here?

I cant seem to find a way to fulfill the dependency.

LightweightinstructionRunner is in a diff package while SchemaRegistry and SchemaRegistryClient are in the same package.

user10938362
  • 3,991
  • 2
  • 12
  • 29
Shitij Goyal
  • 191
  • 1
  • 8

1 Answers1

3

The SchemaRegistryClient to be used has to be in scope for the macro to find it. You could declare an abstract def for it in your EndpointModule (without any parameter, because MacWire does not know which url to put in there)

trait EndpointModule  {
  // Schema Registry endpoint dependency
  def client: SchemaRegistryClient
  lazy val schemaRegistry: SchemaRegistry = wire[SchemaRegistry]
}

object LightweightinstructionRunner extends EndpointModule with ConfigModule {
  override val client = SchemaRegistryClient("")
}

// or maybe

class LightweightinstructionRunner(url: String) extends EndpointModule with ConfigModule {
  override val client = SchemaRegistryClient(url)
}
Thilo
  • 257,207
  • 101
  • 511
  • 656
  • Ahh got it. It's al a game of scopes! But then how do I fill in a url as a parameter? In this implementation, I would have to harcode the url or get it from a config within this method. Is there a way to pass it from another method, when I actually use the client? – Shitij Goyal May 24 '20 at 12:54
  • Not sure what you mean. You have to provide a `val` with the instance you want MacWire to wire into other things. How you create that `val` is completely up to you. The `LightweightinstructionRunner` could be a `class` that takes that String as a constructor parameter for example. – Thilo May 24 '20 at 14:00
  • Yeah that would work. But what if I want to insert a runtime value? Creating an object from within a method. Seems like macwire needs the dependencies to be available at compile time which makes sense but then using the declaring abstract members without params and then overriding them can only give a default implementation as I can't change its behaviour, due to no params. – Shitij Goyal May 24 '20 at 17:21
  • Well, it is a *compile-time* dependency injection framework. All dependencies are resolved at compile time. These dependencies can still configure themselves at runtime, of course, for example by reading from configuration files. – Thilo May 25 '20 at 02:04
  • Maybe you need to explain your use-case more. But usually, if you want a different implementation (for example for testing), you inject a different set of dependencies. Instead of the `EndpointModule` or the calling code figuring out what implementation you need, you have different modules for different environments (each of them "hard-coded" with the appropriate implementations) and wire up the one that is appropriate into the application. – Thilo May 25 '20 at 02:08