{"id":37196570,"url":"https://github.com/michaelrocks/lightsaber","last_synced_at":"2026-01-14T22:52:11.369Z","repository":{"id":29901451,"uuid":"33447127","full_name":"MichaelRocks/lightsaber","owner":"MichaelRocks","description":"Compile time dependency injection framework for JVM languages. Especially for Kotlin.","archived":false,"fork":false,"pushed_at":"2020-05-14T13:25:03.000Z","size":2162,"stargazers_count":119,"open_issues_count":2,"forks_count":8,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-08-01T00:31:07.434Z","etag":null,"topics":["android","dependency-injection","di","java","kotlin"],"latest_commit_sha":null,"homepage":"","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/MichaelRocks.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-04-05T16:29:00.000Z","updated_at":"2025-04-27T08:44:38.000Z","dependencies_parsed_at":"2022-08-23T04:50:25.731Z","dependency_job_id":null,"html_url":"https://github.com/MichaelRocks/lightsaber","commit_stats":null,"previous_names":[],"tags_count":30,"template":false,"template_full_name":null,"purl":"pkg:github/MichaelRocks/lightsaber","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MichaelRocks%2Flightsaber","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MichaelRocks%2Flightsaber/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MichaelRocks%2Flightsaber/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MichaelRocks%2Flightsaber/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/MichaelRocks","download_url":"https://codeload.github.com/MichaelRocks/lightsaber/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MichaelRocks%2Flightsaber/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28437022,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T22:37:52.437Z","status":"ssl_error","status_checked_at":"2026-01-14T22:37:31.496Z","response_time":107,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","dependency-injection","di","java","kotlin"],"created_at":"2026-01-14T22:52:10.446Z","updated_at":"2026-01-14T22:52:11.337Z","avatar_url":"https://github.com/MichaelRocks.png","language":"Kotlin","readme":"[![Build Status](https://travis-ci.org/MichaelRocks/lightsaber.svg?branch=develop)](https://travis-ci.org/MichaelRocks/lightsaber)\n\nLightsaber\n==========\n\nCompile time dependency injection framework for JVM languages. Especially for Kotlin.\n\nWhy?\n----\n\nThis framework is inspired by two projects: Guice and Dagger. While Guice is a quite small but a very powerful library\nit's not efficient enough on Android as it relies on reflection at runtime. On the other hand Dagger makes all\nits magic at compile time and thus is very efficient. However, Dagger uses APT under the hood, what may become a problem\nwhen used not from Java.\n\nThe goal of Lightsaber is to provide lightning-fast compile time dependency injection and not to rely on APT at the same\ntime so that the library can be used with almost any JVM language and on Android.\n\nUsage\n-----\n\n### Configuration\n\n```groovy\nbuildscript {\n  repositories {\n    jcenter()\n  }\n\n  dependencies {\n    classpath 'io.michaelrocks:lightsaber-gradle-plugin:0.14.1-beta'\n  }\n}\n\n// For Android projects.\napply plugin: 'com.android.application'\napply plugin: 'io.michaelrocks.lightsaber.android'\n\n// For other projects.\napply plugin: 'java'\napply plugin: 'io.michaelrocks.lightsaber'\n\n// Optional, just if you need Kotlin extension functions.\ndependencies {\n  implementation 'io.michaelrocks:lightsaber-core-kotlin:0.14.1-beta'\n}\n```\n\n### Declaring dependencies\n\nThe primary goal of a DI framework is to inject dependencies into your code. Lightsaber can do that with constructor,\nfield, and method injection. In order to make injection work you have to annotate a method or a field with the `@Inject`\nannotation and [provide dependencies](#providing-dependencies) in other parts of the project.\n\n#### Constructor injection\n\nConstructor injection is the most proper way of performing injection. All you have to do is to annotate a constructor of\na class with `@Inject`. Lightsaber will be able to provide values for the arguments of the constructor and to create\nan instance of the class using this constructor. Moreover, when using constructor injection the class becomes eligible\nfor provision, that is this class itself can be used as a dependency. Lightsaber requires neither the class, nor the\ninjectable constructor to be `public`.\n\n```java\npublic class Droid {\n  @Inject\n  public Droid(Battery battery) {\n  }\n}\n```\n\n#### Field injection\n\nSometimes you don't manage instantiation of a class. In this case you cannot use constructor injection. But you can\nstill use dependency injection for such classes. The easiest way to do that is to inject dependencies right into fields\nof your class. To inform Lightsaber which fields it needs to inject you have to annotate them with `@Inject`.\nAgain, Lightsaber doesn't require the injectable field to be `public` or `final`.\n\n```java\npublic class Droid {\n  @Inject\n  private Battery battery;\n}\n```\n\n#### Method injection\n\nIn some cases you may want Lightsaber to call a method of a class after all fields of the class have been injected.\nJust annotate the method with `@Inject` and Lightsaber will provide values for the arguments of the method and invoke\nit. And as always, Lightsaber doesn't need the method to be `public`.\n\n```java\npublic class Droid {\n  private Battery battery;\n\n  @Inject\n  public void setBattery(Battery battery) {\n    this.battery = battery;\n  }\n}\n```\n\n#### Injection order\n\nLet's assume there's a class with constructor, fields, and methods marked as injectable . This class may have ancestor\nclasses with injectable fields and methods. When instantiating this class Lightsaber will perform injection in the\nfollowing order.\n\n1. Instantiate the class via its injectable constructor.\n2. Inject fields starting from ancestor classes.\n3. Invoke injectable methods starting from ancestor classes. The order of injectable method invocations is undefined.\n\n### Providing dependencies\n\nIn order to be able to inject a dependency you have to provide this dependency first. In other words you have to tell\nLightsaber what it have to return when requested a dependency of some type. This can be done in three ways: using\nmodules and their provider methods, via injectable constructors mentioned earlier, and by using the `@ProvidedAs`\nannotation.\n\n#### Provider methods\n\nLightsaber requires provider methods to be defined in modules that need to be combined into components.\n\n##### Modules\n\nA module is a logical unit responsible for providing dependencies belonging to the module. Module classes must be\nannotated with the `@Module` annotation. A module can contain a number of provider methods. Lightsaber treats a method\nas a provider method if it's annotated with the `@Provide` annotation. When a type is provided by a provider method\nit can be injected into a class in other parts of the project. Neither the module nor its provider methods are required\nto be `public`.\n\n```java\n@Module\npublic class DroidModule {\n  @Provide\n  public Droid provideDroid() {\n    return new Droid();\n  }\n}\n```\n\nNote that when manually creating a dependency Lightsaber doesn't perform field and method injection into the returned\ninstance. But you can do that via [manual injection](#manual-injection) or by creating a dependency with an\n[injectable constructor](#injectable-constructors).\n\n##### Components\n\nTo make Lightsaber aware of modules and their provided dependencies the modules have to be organized into a component.\nA component is just a class annotated with the `@Component` annotation. The goal of this class is to import modules\nto Lightsaber. Every method that imports a module must be annotated with `@Import`. Moreover, a component can provide\nits own dependencies, just like a module. Neither the component class itself nor its provider methods have to be\n`public`.\n\n```java\n@Component\npublic class DroidComponent {\n  @Import\n  public DroidModule importDroidModule() {\n    return new DroidModule();\n  }\n}\n```\n\nOne of the reasons why you need a component is that its instance should be passed as an arguments to a method that\ncreates an `Injector`. Finally, when a component is defined you can create an injector with this component.\n\n```\nLightsaber lightsaber = new Lightsaber.Builder().build(); \nInjector injector = lightsaber.createInjector(DroidComponent());\n```\n\nThe `createInjector()` method accepts a single component and returns an injector that can provide any dependency from\nany module of the component and from any class with an [injectable constructor](#injectable-constructors).\n\n##### Nested modules \n\nNot only components can import modules but modules can import other modules too. So if you have a reusable module\nwith some common dependencies you can import it to another module the same way you import it to a component:\n\n```java\n@Module\npublic class CommonDroidModule {\n  @Provide\n  public Battery provideBattery() {\n    return new Battery();\n  }\n}\n\n@Module\npublic class DroidModule {\n  @Import\n  public CommonDroidModule importCommonDroidModule() {\n    return new CommonDroidModule();\n  }\n}\n```  \n\n##### Inversion of import\n\nSometimes you may want to specify that a module should be imported by another modules and/or components without\nmodifying them. It can be achieved by applying the `@ImportedBy` annotation to the module that needs to be imported:\n\n```java\n@Component\npublic class DroidComponent {\n  /* ... */\n}\n\n@Module\n@ImportedBy(DroidComponent.class)\npublic class DroidModule {\n  /* ... */\n}\n``` \n\n#### Injectable constructors\n\nA class may have one and only one injectable constructor. This constructor must be annotated with `@Inject` and can\nhave any number of arguments. When instantiating a class with an injectable constructor via an injector the injector\nmust be able to provide instances for every argument of the constructor.\n\nClasses with injectable constructors should be bound to a module and thus to a component that provides the module.\nThis binding can be defined by annotating the class with `@ProvidedBy` annotation and specifying module classes in its\ndefault parameter.\n\n```java\n@ProvidedBy(DroidModule.class)\npublic class Droid {\n  @Inject\n  public Droid(Battery battery) {\n  }\n}\n```\n\nIf you have a module that should provide most of the dependencies you can make this module default by setting\n`isDefault` parameter in the `@Module` annotation to `true` and avoid using `@ProvidedBy` annotation on classes that\nneed to be provided by this module.\n\nWhen providing a dependency using an injectable constructor Lightsaber will perform field and method injection into\nthe provided instance.\n\n#### `@ProvidedAs` annotation\n\nThe `@ProvidedAs` annotation can be used to bind an interface to an implementation when you don't want to define a\nprovider method in a module. Let's assume you have a `Droid` interface and its `ElectricalDroid` implementation and\nyou want to provide an `ElectricalDroid` instance as a `Droid` dependency.\n\n```java\npublic interface Droid {\n}\n\npublic class ElectricalDroid implements Droid {\n  private Battery battery;\n\n  @Inject\n  public ElectricalDroid(Battery battery) {\n    this.battery = battery;\n  }\n\n  /* ... */\n}\n```\n\nYou can achieve that by adding a provider method to a module:\n\n```java\n@Module\npublic class DroidModule {\n  @Provide\n  public Droid provideDroid(final ElectricalDroid droid) {\n    return droid;\n  }\n}\n```\n\nBut this approach would require the `DroidModule` to be aware of the `ElectricalDroid` implementation, which isn't\nalways the case. Another way to do that is to annotate `ElectricalDroid` with the `@ProvidedAs` annotation:\n\n```java\n@ProvidedAs(Droid.class)\npublic class ElectricalDroid implements Droid {\n  /* ... */\n}\n```\n\n### Manual injection\n\nManual injection is a way to create an instance of a provided type or to perform field and method injection into an\nexisting object. An instance can be obtained by calling the `getInstance()` method of the `Injector`:\n\n```\nDroid droid = injector.getInstance(Droid.class);\n```\n\nIf you need a factory that provides instances of a given type you can get a `Provider` object from the `Injector`.\nThen you'll be able to get an instance from the `Provider` by calling its `get()` method: \n\n```\nProvider\u003cDroid\u003e droidProvider = injector.getProvider(Droid.class);\nDroid droid = droidProvider.get();\n```\n\nWhen creating an instance of a dependency manually Lightsaber performs field and method injection for this instance.\nBut sometimes you already have an instance and want to inject dependencies into it. You can do that by calling the\n`injectMember()` method of the `Injector` passing the instance to it.\n\n```java\npublic class DroidController {\n  @Inject\n  private Droid droid;\n\n  public void initialize(Injector injector) {\n    injector.injectMembers(this);\n  }\n}\n```\n\nConsider the following example. We have a `Droid` interface and its implementation and we want to provide `Droid` as a\ndependency.\n\n```java\npublic interface Droid {\n  /* ... */\n}\n\npublic class ElectricalDroid implements Droid {\n  @Inject\n  private Battery battery;\n\n  /* ... */\n}\n```\n\nIf we just create an `ElectricalDroid` instance and return it from a provider method the `battery` field will not be\ninitialized because Lightsaber doesn't perform injection into instances it doesn't manage. But we can fix that by\nmanually injecting dependencies into the instance using the `injectMembers()` method.\n\n```java\n@Module\npublic class DroidModule {\n  @Provide\n  public Droid provideDroid(Injector injector) {\n    Droid droid = new ElectircalDroid();\n    injector.injectMemebers(droid);\n    return droid;\n  }\n}\n```\n\nWhile this is a working example it can be refactored to using constructor injection. In this case manual injection\nbecomes unnecessary.\n\n```java\npublic class ElectricalDroid implements Droid {\n  private Battery battery;\n\n  @Inject\n  public ElectricalDroid(Battery battery) {\n    this.battery = battery;\n  }\n\n  /* ... */\n}\n```\n\n```java\n@Module\npublic class DroidModule {\n  @Provide\n  public Droid provideDroid(ElectricalDroid droid) {\n    return droid;\n  }\n}\n```\n\n### Singleton injection\n\nBy default Lightsaber creates a new instance every time a dependency is requested. This behavior can be changed so that\nLightsaber will return a single instance of the dependency for a given injector. All you need to do is to apply the\n`@Singleton` annotation to a class with an injectable constructor or to a provider method.\n\n```java\n@Singleton\npublic class ElectricalDroid implements Droid {\n  /* ... */\n}\n```\n\n```java\n@Module\npublic class DroidModule {\n  @Provide\n  @Singleton\n  public Droid provideDroid(ElectricalDroid droid) {\n    return droid;\n  }\n}\n```\n\nIn the example above you can annotate just a class or just a provider method or both the class and the provider method\nwith the `@Singleton` annotation and behavior will be very similar but not exactly the same.\n\nIf the `ElectricalDroid` is a singleton then one and only one instance of this class will be created per an injector\ninstance. And even if the `provideDroid()` method is not annotated with `@Singleton` it will return the same instance\nevery time it's called because it returns a singleton instance of `ElectricalDroid`.\n\nOn the other hand, if the `ElectricalDroid` class isn't a singleton the `provideDroid()` method annotated with\n`@Singleton` will return a cached instance of `ElectricalDroid` so the instance will always be the same. But if\n`ElectricalDroid` is injected somewhere else a new instance of this class will be created.\n\n### Lazy injection\n\nInstead of creating a dependency instance at injection time its instantiation can be deferred until the object is really\nneeded. For this purpose Lightsaber has a generic `Lazy` interface that can be injected instead of the dependency.\n\n```java\npublic class Droid {\n  @Inject\n  private Lazy\u003cBattery\u003e battery;\n\n  public void charge() {\n    battery.get().charge();\n  }\n}\n```\n\nIn this example a `Battery` instance will be created only when `battery.get()` is called.\n\n### Provider injection\n\nProvider injection is somewhat similar to lazy injection with one major difference: when `Provider.get()` is called\nmultiple times you can receive either the same instance of a dependency or a different instance on each invocation of\nthe `get()` method. Provider injection is useful when you need to pass some arguments to a constructor of an object\nwhile other arguments should be provider by an injector.\n\n```java\npublic class Droid {\n  public Droid(Battery battery, Adapter adapter) {\n    /* ... */\n  }\n}\n```\n\n```java\npublic class DroidFactory {\n  @Inject\n  private Provider\u003cBattery\u003e batteryProvider;\n\n  public Droid createDroidWithAdapter(Adapter adapter) {\n    return new Droid(batteryProvider.get(), adapter);\n  }\n}\n```\n\n### Qualified injection\n\nSometimes you may want to provide different implementations of a single dependency type. You can do that by applying a\nqualifier annotation to a class with an injectable constructor or to a provider method. Then you need to apply the same\nqualifier annotation to the provided dependency at the injection point. A dependency may have either no qualifiers or a\nsingle one.\n\nIn the next example we will create a module that provides two different instances of the `Droid` class. To make\nLightsaber distinguish between these dependencies we will annotate them with the built-in `@Named` qualifier.\n\n```java\n@Module\npublic class DroidModule {\n  @Provide\n  @Singleton\n  @Named(\"R2-D2\")\n  public Droid provideR2D2() {\n    return new Droid(\"R2-D2\");\n  }\n\n  @Provide\n  @Singleton\n  @Named(\"C-3PO\")\n  public Droid provideC3PO() {\n    return new Droid(\"C-3PO\");\n  }\n\n  @Provide\n  @Singleton\n  public Droid provideUnknownDroid() {\n    return new Droid(\"Unknown\");\n  }\n}\n```\n\n```java\npublic class DroidParty {\n  @Inject\n  @Named(\"R2-D2\")\n  private Droid r2d2;\n\n  @Inject\n  @Named(\"C-3PO\")\n  private Droid c3po;\n\n  @Inject\n  private Droid unknownDroid;\n}\n```\n\n#### Custom qualifiers\n\nBesides using the `@Named` qualifier you can create you own one. To do that you need to create an annotation and\nannotate it with the `@Qualifier` annotation.\n\n```java\npublic enum DroidType { R2D2, C3PO }\n\n@Qualifier\n@Retention(RetentionPolicy.RUNTIME)\n@Target({\n    ElementType.TYPE,\n    ElementType.FIELD,\n    ElementType.METHOD,\n    ElementType.PARAMETER\n})\npublic @interface Model {\n  DroidType value();\n}\n```\n\n```java\n@Module\npublic class DroidModule {\n  @Provide\n  @Singleton\n  @Model(DroidType.R2D2)\n  public Droid provideR2D2() {\n    return new Droid(\"R2-D2\");\n  }\n\n  @Provide\n  @Singleton\n  @Model(DroidType.C3PO)\n  public Droid provideC3PO() {\n    return new Droid(\"C-3PO\");\n  }\n}\n```\n\n```java\npublic class DroidParty {\n  @Inject\n  @Model(DroidType.R2D2)\n  private Droid r2d2;\n\n  @Inject\n  @Model(DroidType.C3PO)\n  private Droid c3po;\n}\n```\n\nCustom qualifiers are allowed to have any number of properties of any type. When resolving dependencies Lightsaber\ncompares qualifiers by their types and equality of all their properties.\n\n### Generic injection\n\nWith Lightsaber you can inject dependencies of generic types. The generic dependency has to be a parameterized type\nand its type parameters cannot contain wildcards and type variables.\n\nFor example, these types you can use for injection:\n\n- `List\u003cString\u003e`\n- `Map\u003cString, Collection\u003cString\u003e\u003e`\n- `Collection\u003cint[]\u003e`\n\nAnd these types you cannot use:\n\n- `List\u003c? extends CharSequence\u003e`\n- `Map\u003cString, T\u003e`\n\n### Child injection\n\nWhen defining a component you can specify any number of parent components of the component. Given an injector created\nwith one of the parent components you can create a child injector by passing an instance of the child component to\nthe `createChildInjector()` method of the `Injector` interface.\n\nThe child injector inherits all the dependencies of its ancestor components, overrides the `Injector` dependency with\nitself, and adds dependencies defined in its component. At the moment Lightsaber doesn't support dependency overriding\nso all the components in a component chain must have distinct dependencies provided.\n\nConsider the following case. In different parts of an application we need to construct droids. But depending on\na construction point we need to inject a battery of the corresponding type into a droid.\n\nThe following classes define a component that provides droids. Each droid accepts a `Battery` as a dependency.\n\n```java\npublic class ElectricalDroid implements Droid {\n  private Battery battery;\n\n  @Inject\n  public ElectricalDroid(Battery battery) {\n    this.battery = battery;\n  }\n\n  /* ... */\n}\n```\n\n```java\n@Module\npublic class DroidModule {\n  @Provide\n  @Singleton\n  public Droid provideDroid(ElectricalDroid droid) {\n    return droid;\n  }\n}\n```\n\n```java\n@Component\npublic class DroidComponent {\n  @Import\n  public DroidModule importDroidModule() {\n    return new DroidModule();\n  }\n}\n```\n\nAs you can see the `Battery` is not provided anywhere. Here's our trivial `Battery` class.\n\n```java\npublic class Battery {\n  private String name;\n\n  public Battery(String name) {\n    this.name = name;\n  }\n\n  /* ... */\n}\n```\n\nLet's define a component that provides a `Battery` with a given name.\n\n```java\n@Module\npublic class BatteryModule {\n  private String name;\n\n  public BatteryModule(String name) {\n    this.name = name;\n  }\n\n  @Provide\n  public Droid provideBattery() {\n    return new Battery(name);\n  }\n}\n```\n\n```java\n@Component(parent = DroidComponent.class)\npublic class BatteryComponent {\n  private String name;\n\n  public BatteryComponent(String name) {\n    this.name = name;\n  }\n\n  @Import\n  public BatteryModule importBatteryModule() {\n    return new BatteryModule(name);\n  }\n}\n```\n\nNow we can create child injectors passing different instances of the `BatteryComponent` class to the\n`createChildInjector()` method.\n\n```\nLightsaber lightsaber = new Lightsaber.Builder().build();\nInjector droidInjector = lightsaber.createInjector(new DroidComponent());\nInjector nuclearBatteryInjector = \n    droidInjector.createChildInjector(new BatteryComponent(\"Nuclear\"));\nInjector plasmBatteryInjector =\n    droidInjector.createChildInjector(new BatteryComponent(\"Plasm\"));\n\nDroid nuclearBatteryDroid = nuclearBatteryInjector.getInstance(Droid.class);\nDroid plasmBatteryDroid = plasmBatteryInjector.getInstance(Droid.class);\n```\n\nIn the example above we created two singleton instances of the `ElectricalDroid` class passing different instances of\nthe `Battery` class to them. Please, note that if for some reason a singleton dependency was instantiated via a parent\ninjector and then child injectors were created the child injectors would return the same singleton instance created by\nthe parent injector.\n\n### Factories (assisted injection)\n\nIn some cases you may want to instantiate an object passing some arguments to its constructor from an injector and\nprovide some other arguments manually at the instantiation site.\n\nLet's define a `Droid` class that has a constructor with two parameters: a battery and a model:\n\n```java\npublic class Droid {\n  private final Battery battery;\n  private final String model;\n  \n  @Factory.Inject\n  public Droid(Battery battery, @Factory.Parameter String model) {\n    this.battery = battery;\n    this.model = model;\n  }\n  \n  /* ... */\n}\n```\n\n`Droid`'s constructor is annotated with `@Factory.Inject` annotation. This annotation means that this constructor can be\nused for injections but some of its arguments aren't provided by injector's component. Now let's define a module that\nwill be used for providing a `Battery` for the `Droid`:\n\n```java\n@Module\npublic class DroidModule {\n  @Provide\n  public Battery provideBattery() {\n    return new Battery();\n  }\n}\n```\n\nAs you can see no `String` dependency is provided by the module. In order to create a `Droid` we have to provide a model\nname indirectly at the instantiation site. Lightsaber offers a way to achieve that by supporting factories that can\naccept any arguments and pass them to injectable constructors. \n\n```java\n@Factory\n@ProvidedBy(DroidModule.class)\npublic interface DroidFactory {\n  Droid assembleDroid(String model);\n}\n```\n\nThe factory must be an interface annotated with `@Factory` annotation and may contain any number of factory methods. \nThe factory method may contain any number of parameters with unique types. If you need the factory method to contain \nmultiple parameters of the same type they have to be annotated with different qualifiers like `@Named(\"parameterName\")`.\nLightsaber matches factory method's parameters with constructor's parameters annotated with `@Factory.Parameter` by\na type and a qualifier. A component that provides a factory must provide dependencies for all constructor's parameters\nthat aren't annotated with `@Factory.Parameter`.\n\nAfter the factory is defined as shown above it can be injected or retrieved manually from an injector as any other\ndependency:\n\n```java\npublic class DroidParty {\n  @Inject\n  public DroidParty(DroidFactory factory) {\n    Droid r2d2 = factory.assembleDroid(\"R2-D2\");\n    Droid c3po = factory.assembleDroid(\"C-3PO\");\n  }\n}\n```\n\nThe dependency type is resolved from the return type of the factory method by default. You can change this behavior by annotating\nthe factory method with `@Factory.Return` annotation with the actual dependency type as an argument:\n\n```java\npublic interface Droid {\n  /* ... */\n}\n\npublic class ElectricalDroid {\n  private final Battery battery;\n  private final String model;\n  \n  @Factory.Inject\n  public Droid(Battery battery, @Factory.Parameter String model) {\n    this.battery = battery;\n    this.model = model;\n  }\n  \n  /* ... */\n}\n\n@Factory\n@ProvidedBy(DroidModule.class)\npublic interface DroidFactory {\n  @Factory.Return(ElectricalDroid.class)\n  Droid assembleDroid(String model);\n}\n```\n\n### Provider interceptors\n\nWhen writing tests you may need to substitute a real dependency with a mock. To be able to do that you can register a `ProviderInterceptor` when\ncreating a `Lightsaber` instance and replace a provider with the one that returns mocks:\n\n```java\nLightsaber lightsaber = new Lightsaber.Builder()\n    .addProviderInterceptor(\n        new ProviderInterceptor() {\n          @Override\n          public Provider\u003c?\u003e intercept(ProviderInterceptor.Chain chain, Key\u003c?\u003e key) {\n            if (key.getType() == Battery.class) {\n              return new Provider\u003cObject\u003e() {\n                @Override\n                public Object get() {\n                  return new TestBattery();\n                }\n              };\n            } else {\n              return chain.proceed(key);\n            }\n          }\n        }\n    )\n    .build();\n``` \n\n### Testing\n\nTo simplify unit testing and dependency substitution you can add a special testing module to your project's configuration:\n\n```groovy\ndependencies {\n  testImplementation 'io.michaelrocks:lightsaber-test:0.14.1-beta'\n}\n```\n\nThis module allows you to build a `ProviderInterceptor` using a convenient builder API. Moreover, it supports creation of annotation proxies at\nruntime, so you'll be able to deal with qualified dependencies easily.\n\n```java\n// Create a provider of Battery instances.\nProvider\u003cBattery\u003e provider = new Provider\u003cBattery\u003e() {\n  @Override\n  public Battery get() {\n    return new TestBattery();\n  }\n};\n\n// Create a proxy for @Named(\"primary\") annotation.\nNamed annotation = new AnnotationBuilder\u003cNamed\u003e(Named.class)\n    .addMember(\"value\", \"primary\")\n    .build();\n\n// Create a provider interceptor that replaces the primary battery with the test one.\nProviderInterceptor interceptor = new ProviderInterceptorBuilder()\n    .addProviderForClass(Battery.class, annotation, provider)\n    .build();\n\n// Create a Lightsaber instance for unit testing. \nLightsaber lightsaber = new Lightsaber.Builder()\n    .addProviderInterceptor(interceptor)\n    .build();\n``` \n\nLicense\n-------\n\n    Copyright 2019 Michael Rozumyanskiy\n\n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmichaelrocks%2Flightsaber","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmichaelrocks%2Flightsaber","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmichaelrocks%2Flightsaber/lists"}