{"id":21684979,"url":"https://github.com/manuel-mauky/easydi","last_synced_at":"2025-04-12T07:52:10.133Z","repository":{"id":21203490,"uuid":"24516274","full_name":"manuel-mauky/EasyDI","owner":"manuel-mauky","description":"Easy Dependency Injection for Java","archived":false,"fork":false,"pushed_at":"2022-01-31T16:52:20.000Z","size":364,"stargazers_count":52,"open_issues_count":1,"forks_count":9,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-04-12T07:52:05.672Z","etag":null,"topics":["dependency-injection","di-framework","java"],"latest_commit_sha":null,"homepage":null,"language":"Java","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/manuel-mauky.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-09-26T21:41:32.000Z","updated_at":"2024-12-22T15:15:44.000Z","dependencies_parsed_at":"2022-08-27T19:11:59.232Z","dependency_job_id":null,"html_url":"https://github.com/manuel-mauky/EasyDI","commit_stats":null,"previous_names":["lestard/easydi"],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/manuel-mauky%2FEasyDI","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/manuel-mauky%2FEasyDI/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/manuel-mauky%2FEasyDI/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/manuel-mauky%2FEasyDI/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/manuel-mauky","download_url":"https://codeload.github.com/manuel-mauky/EasyDI/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248537033,"owners_count":21120690,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["dependency-injection","di-framework","java"],"created_at":"2024-11-25T16:17:43.783Z","updated_at":"2025-04-12T07:52:10.111Z","avatar_url":"https://github.com/manuel-mauky.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# EasyDI - Dependency Injection for Java\n\n[![Build Status](https://travis-ci.org/lestard/EasyDI.svg?branch=master)](https://travis-ci.org/lestard/EasyDI)\n\n**EasyDI** is a small dependency injection (DI) library for java projects.\n\nIt's designed for small projects that don't need a full-blown DI-framework.\nTo be as easy as possible EasyDI has fewer features compared to other DI frameworks and some limitations:\n\n- Only constructor injection is supported, **no** setter/field injection\n- No `PostConstruct` or `PreDestroy`\n- Uses some JSR-330 annotations (`jakarta.inject.*`, formerly `javax.inject.*`) but is **not** a compliant implementation of JSR-330\n\nIf you like to use dependency injection but EasyDI doesn't fit your needs\n you might want to try other DI frameworks like [CDI](http://www.cdi-spec.org/), [Guice](https://github.com/google/guice)\n or [Dagger](https://square.github.io/dagger/).\n\n## Links\n\n[JavaDoc 0.6.0](https://lestard.github.io/EasyDI/docs/0.6.0/eu/lestard/easydi/EasyDI.html)\n\n\n## Maven Dependencies\n\n**EasyDI** releases are available in the Maven Central Repository.\nYou can use it like this:\n\n### Stable release\n\n#### Gradle\n\n```groovy\nrepositories {\n    mavenCentral()\n}\n\ndependencies {\n    compile 'eu.lestard:easy-di:0.6.0'\n}\n```\n\n#### Maven\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003eeu.lestard\u003c/groupId\u003e\n    \u003cartifactId\u003eeasy-di\u003c/artifactId\u003e\n    \u003cversion\u003e0.6.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n### Current Development version (Snapshot)\n\nThe development version is published automatically to the Sonatype Snapshot repository.\n\n\n#### Gradle\n```groovy\nrepositories {\n    maven {\n        url \"https://oss.sonatype.org/content/repositories/snapshots/\"\n    }\n}\n\ndependencies {\n    compile 'eu.lestard:easy-di:0.7.0-SNAPSHOT'\n}\n```\n\n#### Maven\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003eeu.lestard\u003c/groupId\u003e\n    \u003cartifactId\u003eeasy-di\u003c/artifactId\u003e\n    \u003cversion\u003e0.7.0-SNAPSHOT\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n\n\n## Tutorial\n\nIn the wiki there is a tutorial where all features of EasyDI are described.\nIn the example we are creating a coffee machine application:\n[wiki](https://github.com/lestard/EasyDI/wiki/Tutorial).\n\nThe code for this example is located in the test source directory:\n[/src/test/java/eu/lestard/easydi/examples/coffee/](https://github.com/lestard/EasyDI/tree/master/src/test/java/eu/lestard/easydi/examples/coffee)\n\n## Real-World Examples:\n\n- [SnakeFX](https://github.com/lestard/SnakeFX): A Snake clone written in JavaFX\n- [Nonogram](https://github.com/lestard/nonogram): A nonogram puzzle game written in JavaFX\n\n## How to Use\n\n### 1. Add the library to your project\n\nThere are two ways of using the library in your project:\n\n1. Use a Build-System like Gradle or Maven. **EasyDI** is available in the [Maven Central Repository](https://search.maven.org/#search|ga|1|easy-di). See [Maven dependencies](#dependencies)\n2. Download the ZIP file from the [github release page](https://github.com/lestard/EasyDI/releases/download/v0.3.0/easy-di-0.3.0.zip). The file contains the library JAR file and the JAR for [javax.inject](http://search.maven.org/#artifactdetails|javax.inject|javax.inject|1|jar) which is needed as dependency. Add both JAR files to the classpath of your project.\n\n\n### 2. Create your classes\n\nWrite your Java classes. When your class needs an instance of another class, simply add this dependency as a constructor parameter.\n\n\n```java\npublic class Car {\n\n    private final Engine engine;\n\n    public Car(Engine engine){\n        this.engine = engine;\n    }\n\n    public void drive() {\n        engine.start();\n        engine.accelerate();\n    }\n}\n\npublic class Engine {\n    public void start(){\n        ...\n    }\n\n    public void accelerate(){\n        ...\n    }\n}\n```\n\n### 3. Use EasyDI to get instances of your classes\n\n```java\nimport eu.lestard.easydi.EasyDI;\n\npublic class CarApp {\n\n    public static void main(String...args){\n        EasyDI easyDI = new EasyDI();\n\n        final Car car = easyDI.getInstance(Car.class);\n\n        car.drive();\n    }\n}\n```\n\nFor this simple use case EasyDI doesn't need any annotations or configuration.\n\n## Optional Features\n\n### Multiple Constructors\n\nWhen a class has more then one public constructor, you need to tell *EasyDI* which one it should use. This is\ndone with the annotation `javax.inject.Inject`:\n\n```java\npublic class Car {\n    ...\n    @Inject\n    public Car(Engine engine){\n        // this constructor will be used\n        ...\n    }\n\n    public Car(){\n        ...\n    }\n}\n```\n\n### Interfaces and Implementing classes\n\nEasyDI doesn't know which implementing class it should use when an interface type is requested as a dependency.\nYou have to tell it with the `easyDI.bindInterface(interfaceType, implementingType)` method.\n\n```java\npublic interface Engine {}\n\npublic class GasolineEngine implements Engine {}\n\npublic class ElectricMotor implements Engine {}\n\n\nEasyDI easyDi = new EasyDI();\neasyDI.bindInterface(Engine.class, ElectricMotor.class);\n...\n\nfinal Engine engine = easyDI.getInstance(Engine.class);\n\nassertThat(engine).isInstanceOf(ElectricMotor.class);\n```\n\n### Singletons\n\nBy default EasyDI will create new instances every time a dependency is requested. If there should only be a single instance of a specific class you have to tell EasyDI. There are two ways of doing this:\n\n#### 1. @Singleton\n\nThe recommended way is to use the `javax.inject.Singleton` annotation on the class that should be a singleton:\n\n```java\n@Singleton\npublic class Car {\n...\n}\n```\n\n#### 2. EasyDI.markAsSingleton()\n\nYou can mark a class as singleton with the method `markAsSingleton`. This is useful when you for some reason can't\nmodify the source code of the class (i.e. when it is part of a third-party library).\n\n```java\nEasyDI easyDI = new EasyDI();\n\neasyDI.markAsSingleton(ThirdParty.class);\n...\n```\n\n### Providers\n\nIf you like to inject instances of a class that doesn't meet the requirements of EasyDI you can add a `javax.inject.Provider`\nfor this class. There are many use cases where this can be useful:\n\n- There is only a factory method to get instances of this class but no constructors\n- There is no public constructor or there are more than one public constructors and (for some reason) you can't add the `@Inject` annotation\n- The class is implemented with the [classical Singleton design pattern](https://en.wikipedia.org/wiki/Singleton_pattern#Example).\n- You need to make some configuration on the created instance before it can be used for injection.\n- You like to use abstract classes as dependency (see next section)\n\n```java\nEasyDI easyDI = new EasyDI();\n\neasyDI.bindProvider(Engine.class, new Provider\u003cEngine\u003e() {\n    @Override\n    public Engine get(){\n        Engine engine = new Engine();\n        engine.configureThis();\n        engine.configureThat();\n        return engine;\n    }\n});\n```\n\nWith Java 8 lambdas you would write this:\n\n```java\neasyDI.bindProvider(Engine.class, ()-\u003e {\n    Engine engine = new Engine();\n    engine.configureThis();\n    engine.configureThat();\n    return engine;\n});\n```\n\n\n### Abstract classes\n\nIf an instance of an abstract class is requested, EasyDI can't know out of\nthe box which implementing class it should use.\n\nThis is the same situation as with interfaces. Unlike interfaces at the moment there is no\nexplicit way of defining a binding for abstract classes. The reason is that there are\nfar more possibilities for (miss-)configuration when it comes to (abstract) class bindings.\n\nWhen you like to use abstract classes as dependencies you will have to [create a provider](#providers) for this class.\n\n\n### Lazy injection / lazy instantiation\n\nIn some use cases you need an instance of a class but at the time your constructor is called\nthis dependency isn't available yet or it shouldn't be instantiated at this time.\nInstead you like to retrieve the instance at some later point in time.\n\nAnother similar use case is when you need a dependency only under some conditions and the construction of the dependency is expensive.\n\nIn both cases **lazy injection** is your friend. EasyDI can do lazy injection like this:\n\n1. change the type of the constructor parameter from `T` to `javax.inject.Provider\u003cT\u003e`\n2. call the method `get` on the provider instance when you need the actual instance\n\nExample:\n\n```java\n\npublic class Car {\n\n    private Provider\u003cEngine\u003e engineProvider;\n\n    public Car(Provider\u003cEngine\u003e engineProvider){\n        this.engineProvider = engineProvider;\n    }\n\n    public void buildCar(){\n        Engine engine =  engineProvider.get();\n\n        ...\n    }\n```\n\nIn this example the instance of the `Engine` is only created when the `buildCar` method is called. In this\ncase the normal dependency injection mechanism of EasyDI with all configuration rules described above\nwill run and retrieve an instance of `Engine`.\n\n**Recommendation**:\nIn general lazy injection should only be the last choice when you really can't inject an instance directly in the constructor.\nCode with lazy injection will typically be harder to reason about. It's not trivial anymore to tell at which\npoint in time an instance of your class will be created.\n\n\n\n### Bind instances\n\nIn some use cases you like to define that one specific instance is injected every time the given\ntype is requested. This is like a singleton configuration only that you define the exact instance on your own instead\nof only defining that the given type is a singleton and let EasyDI create the instance.\n\n```java\nEngine engine = new Engine();\neasyDI.bindInstance(Engine.class, engine);\n```\n\nThis is a shortcut for this:\n\n```java\nEngine engine = new Engine();\neasyDI.bindProvider(Engine.class, () -\u003e engine);\n```\n\nThe `bindInstance` method can also be used to configure instances for interfaces or abstract classes.\n\n\n\n### Inject EasyDI context\n\nIn some use cases you like to have access to the EasyDI instance in one of your\nclasses to be able to get other instances at runtime.\n\nTo achieve this use this config:\n\n```java\nEasyDI context = new EasyDI();\ncontext.bindProvider(EasyDI.class, ()-\u003e context);\n```\n\nor\n\n```java\nEasyDI context = new EasyDI();\ncontext.bindInstance(EasyDI.class, context);\n```\n\n\n\nThen you can inject `EasyDI` in you classes:\n\n\n```java\nExample.java:\n\npublic class Example {\n\n    private EasyDI context;\n\n    public Example(EasyDI context){\n        this.context = context;\n    }\n\n    public void doSomething(){\n        Other other = context.getInstance(Other.class);\n        ...\n    }\n}\n\n```\n\n\n**Be aware that there are some drawbacks/characteristics with this approach you should keep in mind:**\n\n- It's harder to reason about your code because the instantiation of classes may be delayed.\n- It may be harder to reason about your EasyDI configuration as it's now possible make configurations in other classes besides the main class.\n- You have a Dependency (`import`) to the EasyDI library in your business code.\nThis makes it harder to change the dependency library afterwards.\n- If you forget the `bindProvider` configuration you will get a new context instance injected every time because the `EasyDI` class isn't marked as singleton. This has several consequences:\n  - The new instance of EasyDI has no configuration. It's a totally different instance as the root context. NO configuration will be inherited from the root context.\n  - The scope of the singleton configuration is limited to a single context. When there are two contexts it's possible that there are two instances of a class that was marked as singleton in your application!\n\n\n**Therefore it's generally not recommended to inject `EasyDÌ` in your classes**. It should only be the last choice when there\nis no other option for your use case.\n\n\n\nIf you need to get instances from the dependency injection container in your business code you should use a `Provider` as \nconstructor argument with the generic type of the classes you want to get. See the [Lazy Injection](#lazy-injection--lazy-instantiation) section.\n\n\nIf you still need the possibility to get instances of various types in your business code you should probably use this approach:\n\n```java\npublic interface InstanceProvider {\n    \u003cT\u003e T getInstance(Class\u003cT\u003e type);\n}\n\n\n\n// in your main class\n\nEasyDI context = new EasyDI();\ncontext.bindProvider(InstanceProvider.class, () -\u003e context::getInstance);\n\n\n\n// in your business code\npublic class Example {\n\n    private InstanceProvider context;\n\n    public Example(InstanceProvider context){\n        this.context = context;\n    }\n\n    public void doSomething(){\n        Other other = context.getInstance(Other.class);\n        ...\n    }\n}\n```\n\nThis approach has some advantages over the previous one:\n- no dependency to the EasyDI library in your business code anymore. This way switching to another DI library in the future should be easier.\n- It's not possible to (accidentally) re-configure the EasyDI context outside of your main class.\n- No way to mess up the singleton scope anymore.\nIf you forget the `bindProvider` configuration in the example you will now get an expressive error message that there is no provider for the interface `InstanceProvider` found.\n\n\n\n\n\n---\n\n## Note on Circular Dependencies\n\nWhen using constructor injection without a DI framework, it isn't possible to\ncreate circular dependencies. Look at the following example:\n\n```java\npublic class A {\n    public A (B b){}\n}\n\npublic class B {\n    public B (C c){}\n}\n\npublic class C {\n    public C (A a){}\n}\n```\n\nYou can't instantiate any of these classes with `new` because you can't provide the needed\nconstructor params (except you pass `null` as constructor param).\n\nThe same is true for EasyDI. If you try to get an instance of one of these classes you will\nget an `IllegalStageException`:\n\n```java\nEasyDI easyDI = new EasyDI();\n\neasyDI.getInstance(A.class); // IllegalStateException\n```\n\nCreating circular dependencies is generally a bad idea because it leads to tight coupling.\nWhile other DI frameworks can circumvent this by creating proxy classes, EasyDI won't!\nInstead you have to [fix your dependency graph](http://misko.hevery.com/2008/08/01/circular-dependency-in-constructors-and-dependency-injection/).\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmanuel-mauky%2Feasydi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmanuel-mauky%2Feasydi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmanuel-mauky%2Feasydi/lists"}