CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-com-softwaremill-macwire--macros

Zero-cost, compile-time, type-safe dependency injection library providing macros for automatic instance creation in Scala applications

Pending
Overview
Eval results
Files

context-free-wiring.mddocs/

Context-Free Wiring

Context-free wiring with autowire creates instances using explicitly provided dependencies, without relying on the surrounding context. This approach is only available in Scala 3 and provides maximum flexibility in dependency specification.

Core Functions

autowire

Creates an instance of type T using provided dependencies. Missing dependencies are automatically created using public constructors or companion object apply methods.

inline def autowire[T](inline dependencies: Any*): T

Parameters:

  • dependencies: Any* - Variable number of dependency specifications

Returns: Instance of type T with all dependencies wired

Dependency Types: Each dependency parameter can be:

  • Instance: Direct instance to use for injection
  • Function: Function that creates an instance when called
  • Class: classOf[SomeType] to instantiate the class for dependency types it implements

Usage Examples

Basic Autowiring

import com.softwaremill.macwire.*

class DatabaseAccess()
class SecurityFilter()
class UserFinder(databaseAccess: DatabaseAccess, securityFilter: SecurityFilter)
class UserStatusReader(userFinder: UserFinder)

// Creates all dependencies automatically
val userStatusReader = autowire[UserStatusReader]()

Generates equivalent code:

val userStatusReader = {
  val wiredDatabaseAccess = new DatabaseAccess()
  val wiredSecurityFilter = new SecurityFilter()
  val wiredUserFinder = new UserFinder(wiredDatabaseAccess, wiredSecurityFilter)
  val wiredUserStatusReader = new UserStatusReader(wiredUserFinder)
  wiredUserStatusReader
}

Providing Instance Dependencies

import java.io.Closeable

class DataSource(jdbcConn: String) extends Closeable { def close() = () }
class DatabaseAccess(ds: DataSource)
class UserFinder(databaseAccess: DatabaseAccess)

// Provide pre-configured DataSource instance
val dataSource = new DataSource("jdbc:postgresql://localhost/mydb")
val userFinder = autowire[UserFinder](dataSource)

Using Factory Functions

class ConfiguredService(config: Config)

// Use function to create dependency
val createService = () => new ConfiguredService(loadConfig())
val someService = autowire[SomeServiceUsingConfiguredService](createService)

Using Class Dependencies

trait Logger
class ConsoleLogger extends Logger
class FileLogger extends Logger
class Service(logger: Logger)

// Specify which Logger implementation to use
val service = autowire[Service](classOf[ConsoleLogger])

Complex Dependency Scenarios

class EmailService(smtpHost: String, port: Int)
class NotificationService(emailService: EmailService, logger: Logger)
class UserService(notificationService: NotificationService)

class AppConfig {
  val smtpHost = "smtp.example.com"
  val smtpPort = 587
  val logger = new ConsoleLogger()
}

val appConfig = new AppConfig()

// Combine multiple dependency sources
val userService = autowire[UserService](
  appConfig.smtpHost,
  appConfig.smtpPort,
  appConfig.logger
)

Behavior and Characteristics

Dependency Resolution Order

  1. Explicit Dependencies: Parameters passed to autowire are checked first
  2. Constructor/Apply Methods: Missing dependencies are created using public constructors or companion object apply methods
  3. Recursive Creation: The process repeats for nested dependencies

Type Matching

  • Dependencies are matched by exact type
  • Subtype relationships are not automatically resolved
  • Generic types are matched with full type parameters

Error Conditions

  • Missing Dependencies: Compile-time error if a required dependency cannot be created or provided
  • Ambiguous Dependencies: Error when multiple instances of the same type are provided
  • Unsupported Types: Primitive types and certain Scala built-in types cannot be autowired
  • Cyclic Dependencies: Detected and reported at compile time

Compilation Requirements

  • Only available in Scala 3
  • Requires the macros library as a "provided" dependency
  • All wiring resolution happens at compile time with zero runtime overhead

Install with Tessl CLI

npx tessl i tessl/maven-com-softwaremill-macwire--macros

docs

context-dependent-wiring.md

context-free-wiring.md

dynamic-instance-access.md

factory-based-wiring.md

index.md

tile.json