diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..8c82fa0
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+# Created by .ignore support plugin (hsz.mobi)
+### Maven template
+target/
\ No newline at end of file
diff --git a/LICENSE.md b/LICENSE.md
new file mode 100644
index 0000000..06138b3
--- /dev/null
+++ b/LICENSE.md
@@ -0,0 +1,21 @@
+# The MIT License (MIT)
+
+Copyright (c) 2017 [MacFJA](https://github.com/MacFJA)
+
+> Permission is hereby granted, free of charge, to any person obtaining a copy
+> of this software and associated documentation files (the "Software"), to deal
+> in the Software without restriction, including without limitation the rights
+> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+> copies of the Software, and to permit persons to whom the Software is
+> furnished to do so, subject to the following conditions:
+>
+> The above copyright notice and this permission notice shall be included in
+> all copies or substantial portions of the Software.
+>
+> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+> THE SOFTWARE.
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..f8e86cd
--- /dev/null
+++ b/README.md
@@ -0,0 +1,154 @@
+# Injector
+
+ - [Injection possibility](#injection)
+ - [Constructor Injection](#injection-constructor)
+ - [Setters Injection](#injection-setters)
+ - [Properties Injection](#injection-properties)
+ - [Method Injection](#injection-method)
+ - [Injection types](#types)
+ - [Installation](#installation)
+ - [Examples](#examples)
+ - [Declaring a mapping](#examples-mapping)
+ - [For a singleton](#examples-mapping-singleton)
+ - [For an interface/abstract class to concrete implementation](#examples-mapping-interface)
+
+## Injection possibility
+
+This library offer several types of injection:
+
+- Constructors injection
+- Setters injection
+- Properties injection
+- Method injection
+
+### Constructor Injection
+
+The constructor injection try to create a class instance by looping over every class constructor until it found one that can be used .
+
+The injection criteria are:
+
+- Parameters are not Java primitive
+- Parameters packages are in injector package list
+- All parameters constructor do the same
+
+### Setters Injection
+
+The setter injection is automatically run after the constructor injection if the injector have the option activated.
+(Can be also be call on an existing instance)
+For a setter method to be injected, it must validate the following conditions:
+
+- The method name **MUST** start with `set`
+- The method **MUST** have exactly one parameter
+- The method **MUST** have the annotation `@javax.inject.Inject`
+- The method parameter must be an injectable class
+
+### Properties Injection
+
+The property injection is automatically run after the constructor injection if the injector have the option activated.
+(Can be also be call on an existing instance)
+For a property to be injected, it must validate the following conditions:
+
+- The property **MUST** be accessible
+- The property **MUST** have the annotation `@javax.inject.Inject`
+- The property must be an injectable class
+
+### Method Injection
+
+A method can have its parameters injected.
+
+There are two way to inject parameters in a method.
+First one is with a `java.lang.reflect.Method` object, in this case there are no control, if a parameter can't be injected `null` will be used.
+The second way is to use the method name, with this way, all method of the object with this name will be try, and the method must have the annotation `@javax.inject.Inject` and every parameters must be injectable.
+
+## Injection types
+
+There are two injection types:
+
+- Singleton
+- Every times a new instance
+
+## Installation
+
+Clone the project:
+```
+git clone https://github.com/MacFJA/Injector.git
+```
+Install the project into your local Maven repository:
+```
+cd Injector/
+mvn clean
+mvn install
+```
+Remove the source:
+```
+cd ..
+rm -r Injector/
+```
+Add the depency in your Maven project:
+```xml
+
+
+
+
+
+ io.github.macfja
+ injector
+ 1.0.0
+
+
+
+
+
+```
+
+## Examples
+
+### Declaring a mapping
+
+#### For a singleton
+
+```java
+io.github.macfja.injector.Injector injector = new io.github.macfja.injector.Injector("mypackage");
+injector.addMapping(new mypackage.MyClass());
+// ... later
+injector.get(mypackage.MyClass.class); // return the instance created in addMapping method
+// ... later
+injector.get(mypackage.MyClass.class); // still the same instance
+```
+
+or
+
+```java
+io.github.macfja.injector.Injector injector = new io.github.macfja.injector.Injector("mypackage");
+injector.addMapping(mypackage.MyClass.class, new io.github.macfja.injector.InjectionUnit(new mypackage.MyClass()));
+// ... later
+injector.get(mypackage.MyClass.class); // return the instance created in addMapping method
+// ... later
+injector.get(mypackage.MyClass.class); // still the same instance
+```
+
+or
+
+```java
+io.github.macfja.injector.Injector injector = new io.github.macfja.injector.Injector("mypackage");
+injector.addMapping(
+ mypackage.MyClass.class,
+ new io.github.macfja.injector.InjectionUnit(
+ mypackage.MyClass.class,
+ io.github.macfja.injector.InjectionUnit.Instantiation.Singleton
+ )
+);
+// ... later
+injector.get(mypackage.MyClass.class); // return the instance created in addMapping method
+// ... later
+injector.get(mypackage.MyClass.class); // still the same instance
+```
+
+#### For an interface/abstract class to concrete implementation
+
+```java
+io.github.macfja.injector.Injector injector = new io.github.macfja.injector.Injector("mypackage");
+injector.addMapping(mypackage.MyInterface.class, new io.github.macfja.injector.InjectionUnit(/* ... */));
+// ... later
+injector.get(mypackage.MyInterface.class); // return an instance according to the InjectionUnit
+```
\ No newline at end of file
diff --git a/doc/Example1.md b/doc/Example1.md
new file mode 100644
index 0000000..b698669
--- /dev/null
+++ b/doc/Example1.md
@@ -0,0 +1,50 @@
+# Example 1
+
+This example is a case where method injection is used (differing class loading).
+
+This approach can also be used for lazy loading.
+
+```java
+package example;
+
+class PanelA extends javax.swing.JPanel {
+ // Do your stuff
+}
+
+class PanelB extends javax.swing.JPanel {
+ // Do other stuff
+}
+
+class Application extends javax.swing.JFrame {
+ private static io.github.macfja.injector.Injector injector = new io.github.macfja.injector.Injector("example");
+
+ public static void main(String[] args) {
+ injector.addMapping(
+ Application.class,
+ new io.github.macfja.injector.InjectionUnit(
+ Application.class,
+ io.github.macfja.injector.InjectionUnit.Instantiation.Singleton
+ )
+ );
+
+ injector.get(Application.class);
+
+ }
+
+ public Application(PanelA panel) {
+ setContentPane(panel);
+ setVisible(true);
+
+ new java.util.Timer().schedule(new java.util.TimerTask() {
+ @Override
+ public void run() {
+ injector.injectIntoMethodName(Application.this, "init");
+ }
+ }, 1000);
+ }
+
+ public void init(PanelB panelB) {
+ setContentPane(panelB);
+ }
+}
+```
\ No newline at end of file
diff --git a/doc/Example2.md b/doc/Example2.md
new file mode 100644
index 0000000..26df89c
--- /dev/null
+++ b/doc/Example2.md
@@ -0,0 +1,78 @@
+# Example 2
+
+This example show the interface use case.
+
+```java
+package example;
+interface ServiceInterface {
+ void connect();
+ void disconnect();
+ void doAction(String param);
+}
+class Application {
+ private ServiceInterface service;
+ public static io.github.macfja.injector.Injector injector;
+
+ public static void main(String[] args) {
+ injector = new io.github.macfja.injector.Injector("example");
+ injector.addMapping(
+ ServiceInterface.class,
+ new io.github.macfja.injector.InjectionUnit(
+ SocketService.class,
+ io.github.macfja.injector.InjectionUnit.Instantiation.Singleton
+ )
+ );
+
+ injector.get(Application.class);
+
+ }
+
+ public Application(ServiceInterface service) {
+ this.service = service;
+
+ doStuff();
+ }
+
+
+ public void doStuff() {
+ service.connect();
+ service.doAction("first");
+ service.doAction("second");
+ service.disconnect();
+ }
+}
+
+class SocketService implements ServiceInterface {
+ @Override
+ public void connect() {
+ // Open socket
+ }
+
+ @Override
+ public void doAction(String param) {
+ // Send data in socket
+ }
+
+ @Override
+ public void disconnect() {
+ // Close socket
+ }
+}
+
+class FileService implements ServiceInterface {
+ @Override
+ public void connect() {
+ // Open file stream
+ }
+
+ @Override
+ public void doAction(String param) {
+ // Write in file
+ }
+
+ @Override
+ public void disconnect() {
+ // Close file stream
+ }
+}
+```
\ No newline at end of file
diff --git a/doc/Mapping.md b/doc/Mapping.md
new file mode 100644
index 0000000..3d19a64
--- /dev/null
+++ b/doc/Mapping.md
@@ -0,0 +1,51 @@
+# Mapping
+
+A mapping is a rule that indicate the _Injector_ how to handle a class.
+
+There are several mapping:
+
+- The singleton mapping (for a given class, the same instance is always return)
+- The interface to implementation (when the interface is requested a new instance of a defined class is provided)
+- The interface to singleton (when the interface is requested a singleton is provided)
+- The parent to child (when requested, a new instance of the defined class children is returned)
+- The parent to child singleton (when requested, a singleton of the defined class children is returned)
+
+## Interface and parent mapping
+
+The **interface to implementation**, the **interface to singleton**, the **parent to child** and the **parent to child singleton** are base on the same principle.
+The method `addMapping` is used in its form:
+```
+public void addMapping(Class, InjectionUnit)
+```
+Where the first parameter is the interface/parent and the second contains information about implementation/child/singleton.
+
+```
+ | First parameter | Second parameter
+-----------------------------+-------------------+------------------------------------------------------------------------------
+ interface to implementation | MyInterface.class | new InjectionUnit(MyImpl.class, InjectionUnit.Instantiation.NewInstance)
+ interface to singleton | MyInterface.class | new InjectionUnit(MyImpl.class, InjectionUnit.Instantiation.Singleton)
+ interface to singleton | MyInterface.class | new InjectionUnit(new MyImpl())
+ parent to child | MyAbstract.class | new InjectionUnit(MyExtender.class, InjectionUnit.Instantiation.NewInstance)
+ parent to child singleton | MyAbstract.class | new InjectionUnit(MyExtender.class, InjectionUnit.Instantiation.Singleton)
+ parent to child singleton | MyAbstract.class | new InjectionUnit(new MyExtender())
+```
+
+## Singleton mapping
+
+There are 3 way to declare a Singleton:
+
+```
+injector.addMapping(new MySingleton());
+```
+
+```
+injector.addMapping(MySingleton.class, new InjectionUnit(new MySingleton()));
+// or
+injector.addMapping(MyInterface.class, new InjectionUnit(new MyImplementation()));
+```
+
+```
+injector.addMapping(MySingleton.class, new InjectionUnit(MySingleton.class, InjectionUnit.Instantiation.Singleton));
+// or
+injector.addMapping(MyInterface.class, new InjectionUnit(MyImplementation.class, InjectionUnit.Instantiation.Singleton));
+```
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..a6df11a
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,108 @@
+
+
+ 4.0.0
+
+ io.github.macfja
+ injector
+ 1.0.0
+ jar
+
+ Injector
+ Classes injector. Injection can be done in constructors, setters, properties and methods
+ https://github.com/MacFJA/Injector
+
+
+
+ MacFJA
+ https://github.com/MacFJA/
+
+
+
+
+ scm:git:git://github.com/MacFJA/Injector.git
+ scm:git:ssh://github.com:MacFJA/Injector.git
+ http://github.com/MacFJA/Injector/tree/master
+
+
+
+
+ MIT License
+ https://opensource.org/licenses/mit-license.php
+ repo
+
+
+
+
+ UTF-8
+
+ 1.7
+ 4.12
+ 1.7.25
+
+
+
+
+
+ org.slf4j
+ slf4j-api
+ ${slf4j.version}
+
+
+
+ javax.inject
+ javax.inject
+ 1
+
+
+
+
+ junit
+ junit
+ ${junit.version}
+ test
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.1
+
+ ${jdk.version}
+ ${jdk.version}
+
+
+
+
+ org.apache.maven.plugins
+ maven-javadoc-plugin
+ 2.10.4
+
+
+ attach-javadocs
+
+ jar
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-source-plugin
+
+
+ attach-sources
+
+ jar
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/io/github/macfja/injector/InjectionUnit.java b/src/main/java/io/github/macfja/injector/InjectionUnit.java
new file mode 100644
index 0000000..886d897
--- /dev/null
+++ b/src/main/java/io/github/macfja/injector/InjectionUnit.java
@@ -0,0 +1,187 @@
+package io.github.macfja.injector;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+
+/**
+ * InjectionUnit class.
+ * Contains information about the class to inject and if the instance must be a singleton or not.
+ *
+ * @author MacFJA
+ */
+public class InjectionUnit implements Cloneable {
+ /**
+ * Class to use when requesting an instance
+ */
+ private final Class toInject;
+ /**
+ * The type of instance
+ */
+ private final Instantiation type;
+ /**
+ * The singleton instance (if the Instantiation is NewInstance)
+ */
+ private Object singleton;
+
+ /**
+ * Simple Constructor
+ *
+ * @param toInject The class that will be used
+ * @param type The type of instance (Singleton or not)
+ */
+ public InjectionUnit(Class toInject, Instantiation type) {
+ this.toInject = toInject;
+ this.type = type;
+ }
+
+ /**
+ * Constructor with a pre-generated singleton;
+ *
+ * @param singletonInstance The singleton to use on later.
+ */
+ public InjectionUnit(Object singletonInstance) {
+ this.toInject = singletonInstance.getClass();
+ this.singleton = singletonInstance;
+ this.type = Instantiation.Singleton;
+ }
+
+ /**
+ * Check if a class have at least one constructor that can be used
+ *
+ * @param toInject The class to check
+ * @param injector The class injector
+ * @return {@code true} if a constructor can be use
+ */
+ public static Boolean isInstantiable(Class toInject, Injector injector) {
+ for (Constructor constructor : toInject.getConstructors()) {
+ if (isConstructorInjectable(constructor, injector)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Check if a constructor can be use (no params, or all params can be injected)
+ *
+ * @param constructor The constructor to check
+ * @param injector The class injector
+ * @return {@code true} if the constructor can be use
+ */
+ public static Boolean isConstructorInjectable(Constructor constructor, Injector injector) {
+ for (Class variable : constructor.getParameterTypes()) {
+ if (!injector.isInjectable(variable)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Get an instance
+ *
+ * @return The instance
+ * @throws IllegalAccessException if this {@code Constructor} object is enforcing Java language access control
+ * and the underlying constructor is inaccessible.
+ * @throws InvocationTargetException if the underlying constructor throws an exception.
+ * @throws InstantiationException if the class that declares the underlying constructor represents
+ * an abstract class.
+ */
+ public Object get(Injector parent) throws IllegalAccessException, InvocationTargetException, InstantiationException {
+ if (Instantiation.Singleton.equals(type)) {
+ if (singleton == null) {
+ singleton = build(parent);
+ }
+ return singleton;
+ }
+ return build(parent);
+ }
+
+ /**
+ * Create an instance of toInject class
+ *
+ * @param parent The parent injector (which initiate the build)
+ * @return The new instance
+ * @throws IllegalAccessException if this {@code Constructor} object is enforcing Java language access control
+ * and the underlying constructor is inaccessible.
+ * @throws InstantiationException if the class that declares the underlying constructor
+ * represents an abstract class.
+ * @throws InvocationTargetException if the underlying constructor throws an exception.
+ */
+ private Object build(Injector parent) throws IllegalAccessException, InstantiationException, InvocationTargetException {
+ Object instance = null;
+
+ if (toInject.getConstructors().length == 0) {
+ instance = toInject.newInstance();
+ } else {
+ for (Constructor constructor : toInject.getConstructors()) {
+ if (isConstructorInjectable(constructor, parent)) {
+ instance = runConstructor(constructor, parent);
+ break;
+ }
+ }
+
+ if (instance == null) {
+ throw new InstantiationException();
+ }
+ }
+
+ if (parent.getInjectProperties()) {
+ parent.injectIntoProperties(instance);
+ }
+ if (parent.getInjectSetters()) {
+ parent.injectIntoSetters(instance);
+ }
+ return instance;
+ }
+
+ /**
+ * Inject class and execute constructor
+ *
+ * @param constructor The constructor to execute
+ * @param parent The parent injector (which initiate the build)
+ * @return A new instance created with the constructor
+ * @throws IllegalAccessException if this {@code Constructor} object is enforcing Java language access control
+ * and the underlying constructor is inaccessible.
+ * @throws InvocationTargetException if the underlying constructor throws an exception.
+ * @throws InstantiationException if the class that declares the underlying constructor
+ * represents an abstract class.
+ */
+ private Object runConstructor(Constructor constructor, Injector parent)
+ throws IllegalAccessException, InvocationTargetException, InstantiationException {
+ ArrayList