Zero-cost, compile-time, type-safe dependency injection library providing macros for automatic instance creation in Scala applications
—
Context-dependent wiring uses dependencies available in the surrounding context (trait, class, or object scope). This family of functions includes wire, wireRec, and wireSet, each providing different approaches to dependency resolution within the current scope.
Creates an instance of type T using dependencies from the surrounding context. Dependencies are resolved from values available in the enclosing scope and inherited scopes.
def wire[T]: TParameters: None (uses type parameter to determine target type)
Returns: Instance of type T with dependencies resolved from context
Behavior:
apply methodCreates an instance of type T with recursive dependency creation. Missing dependencies are automatically created using constructors or apply methods.
def wireRec[T]: TParameters: None (uses type parameter to determine target type)
Returns: Instance of type T with all dependencies created recursively
Behavior:
wireapply methodsCollects all instances of the given type available in the surrounding context.
def wireSet[T]: Set[T]Parameters: None (uses type parameter to determine collection type)
Returns: Set[T] containing all available instances of type T from context
Behavior:
TSet containing all found instancesSet implementation depends on imports in scope (can be mutable or immutable)import com.softwaremill.macwire._
class DatabaseAccess()
class SecurityFilter()
class UserFinder(databaseAccess: DatabaseAccess, securityFilter: SecurityFilter)
trait UserModule {
// Define dependencies in context
lazy val databaseAccess = new DatabaseAccess()
lazy val securityFilter = new SecurityFilter()
// Wire using available context dependencies
lazy val userFinder = wire[UserFinder]
}trait DatabaseModule {
lazy val databaseAccess = new DatabaseAccess()
}
trait SecurityModule {
lazy val securityFilter = new SecurityFilter()
}
trait UserModule extends DatabaseModule with SecurityModule {
// Can wire using dependencies from parent traits
lazy val userFinder = wire[UserFinder]
lazy val userStatusReader = wire[UserStatusReader]
}class DatabaseModule {
lazy val databaseAccess = new DatabaseAccess()
}
class UserModule(databaseModule: DatabaseModule) {
// Import makes dependencies available to wire
import databaseModule._
lazy val securityFilter = new SecurityFilter()
lazy val userFinder = wire[UserFinder]
}class Service1()
class Service2(service1: Service1)
class Service3(service1: Service1, service2: Service2)
trait AppModule {
// wireRec creates missing dependencies automatically
lazy val service3 = wireRec[Service3]
// Equivalent to manually defining:
// lazy val service1 = new Service1()
// lazy val service2 = new Service2(service1)
// lazy val service3 = new Service3(service1, service2)
}trait Plugin
class DatabasePlugin extends Plugin
class CachePlugin extends Plugin
class MetricsPlugin extends Plugin
trait PluginModule {
lazy val databasePlugin = new DatabasePlugin()
lazy val cachePlugin = new CachePlugin()
lazy val metricsPlugin = new MetricsPlugin()
// Collects all Plugin instances
lazy val allPlugins: Set[Plugin] = wireSet[Plugin]
}class ConfiguredService private(config: Config)
object ConfiguredService {
def apply(config: Config): ConfiguredService = new ConfiguredService(config)
}
trait ServiceModule {
lazy val config = loadConfig()
// Uses companion object apply method
lazy val configuredService = wire[ConfiguredService]
}trait WebModule {
// Singleton scope - same instance reused
lazy val singletonService = wire[SingletonService]
// Prototype scope - new instance each time
def prototypeService = wire[PrototypeService]
}trait ConditionalModule {
def isDevelopment: Boolean
lazy val logger = if (isDevelopment) wire[ConsoleLogger] else wire[FileLogger]
}class Repository[T](dao: DAO[T])
class DAO[T]()
trait RepositoryModule {
lazy val userDao = new DAO[User]()
lazy val userRepository = wire[Repository[User]] // Generic types preserved
}trait EmailService
class SmtpEmailService extends EmailService
class SendGridEmailService extends EmailService
trait ServiceModule {
// Specify which implementation to wire
lazy val emailService: EmailService = wire[SmtpEmailService]
}val, lazy val, def in current trait/class/objectimport statementsval and lazy val: Create singleton dependenciesdef: Create new instances on each accessapply methods for complex initialization logicInstall with Tessl CLI
npx tessl i tessl/maven-com-softwaremill-macwire--macros