diff --git a/Injector/.gitignore b/Injector/.gitignore
new file mode 100644
index 0000000..345e61a
--- /dev/null
+++ b/Injector/.gitignore
@@ -0,0 +1,49 @@
+# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
+# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
+
+# User-specific stuff:
+.idea/**/workspace.xml
+.idea/**/tasks.xml
+.idea/dictionaries
+
+# Sensitive or high-churn files:
+.idea/**/dataSources/
+.idea/**/dataSources.ids
+.idea/**/dataSources.xml
+.idea/**/dataSources.local.xml
+.idea/**/sqlDataSources.xml
+.idea/**/dynamic.xml
+.idea/**/uiDesigner.xml
+
+# Gradle:
+.idea/**/gradle.xml
+.idea/**/libraries
+
+# CMake
+cmake-build-debug/
+
+# Mongo Explorer plugin:
+.idea/**/mongoSettings.xml
+
+## File-based project format:
+*.iws
+
+## Plugin-specific files:
+
+# IntelliJ
+out/
+
+# mpeltonen/sbt-idea plugin
+.idea_modules/
+
+# JIRA plugin
+atlassian-ide-plugin.xml
+
+# Cursive Clojure plugin
+.idea/replstate.xml
+
+# Crashlytics plugin (for Android Studio and IntelliJ)
+com_crashlytics_export_strings.xml
+crashlytics.properties
+crashlytics-build.properties
+fabric.properties
diff --git a/Injector/.idea/compiler.xml b/Injector/.idea/compiler.xml
new file mode 100644
index 0000000..bec0f06
--- /dev/null
+++ b/Injector/.idea/compiler.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Injector/.idea/misc.xml b/Injector/.idea/misc.xml
new file mode 100644
index 0000000..e8942bd
--- /dev/null
+++ b/Injector/.idea/misc.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Injector/.idea/modules.xml b/Injector/.idea/modules.xml
new file mode 100644
index 0000000..f21519f
--- /dev/null
+++ b/Injector/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Injector/Injector.iml b/Injector/Injector.iml
new file mode 100644
index 0000000..dc9a8a2
--- /dev/null
+++ b/Injector/Injector.iml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Injector/pom.xml b/Injector/pom.xml
new file mode 100644
index 0000000..6ca3d01
--- /dev/null
+++ b/Injector/pom.xml
@@ -0,0 +1,36 @@
+
+
+ 4.0.0
+
+ ru.spbau.mit.kazakov.Injector
+ Injector
+ 1.0-SNAPSHOT
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+ 1.8
+ 1.8
+
+
+
+
+
+
+
+ junit
+ junit
+ 4.12
+
+
+ org.jetbrains
+ annotations
+ 13.0
+
+
+
+
\ No newline at end of file
diff --git a/Injector/src/main/java/ru/spbau/mit/kazakov/Injector/AmbiguousImplementationException.java b/Injector/src/main/java/ru/spbau/mit/kazakov/Injector/AmbiguousImplementationException.java
new file mode 100644
index 0000000..eaf04b7
--- /dev/null
+++ b/Injector/src/main/java/ru/spbau/mit/kazakov/Injector/AmbiguousImplementationException.java
@@ -0,0 +1,7 @@
+package ru.spbau.mit.kazakov.Injector;
+
+/**
+ * Thrown when found multiple implementations for a dependency.
+ */
+public class AmbiguousImplementationException extends Exception {
+}
diff --git a/Injector/src/main/java/ru/spbau/mit/kazakov/Injector/ImplementationNotFoundException.java b/Injector/src/main/java/ru/spbau/mit/kazakov/Injector/ImplementationNotFoundException.java
new file mode 100644
index 0000000..5b4afea
--- /dev/null
+++ b/Injector/src/main/java/ru/spbau/mit/kazakov/Injector/ImplementationNotFoundException.java
@@ -0,0 +1,7 @@
+package ru.spbau.mit.kazakov.Injector;
+
+/**
+ * Thrown if found no implementation for a dependency.
+ */
+public class ImplementationNotFoundException extends Exception {
+}
diff --git a/Injector/src/main/java/ru/spbau/mit/kazakov/Injector/InjectionCycleException.java b/Injector/src/main/java/ru/spbau/mit/kazakov/Injector/InjectionCycleException.java
new file mode 100644
index 0000000..e61306c
--- /dev/null
+++ b/Injector/src/main/java/ru/spbau/mit/kazakov/Injector/InjectionCycleException.java
@@ -0,0 +1,7 @@
+package ru.spbau.mit.kazakov.Injector;
+
+/**
+ * Thrown if found a circular dependency.
+ */
+public class InjectionCycleException extends Exception {
+}
diff --git a/Injector/src/main/java/ru/spbau/mit/kazakov/Injector/Injector.java b/Injector/src/main/java/ru/spbau/mit/kazakov/Injector/Injector.java
new file mode 100644
index 0000000..ab57151
--- /dev/null
+++ b/Injector/src/main/java/ru/spbau/mit/kazakov/Injector/Injector.java
@@ -0,0 +1,103 @@
+package ru.spbau.mit.kazakov.Injector;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Modifier;
+import java.util.*;
+
+
+/**
+ * A class for creating an object of specified class using given classes.
+ */
+public class Injector {
+ /**
+ * Creates an object of specified class using classes from specified container.
+ *
+ * @param rootClassName specified class
+ * @param implementations for creating an object
+ * @return created object
+ * @throws AmbiguousImplementationException when found multiple implementations for a dependency
+ * @throws ImplementationNotFoundException if found no implementation for a dependency
+ * @throws InjectionCycleException if found a circular dependency
+ * @throws ClassNotFoundException if found not existing class
+ */
+ @NotNull
+ public static Object initialize(@NotNull String rootClassName, @NotNull List implementations) throws Exception {
+ return create(rootClassName, implementations, new TreeSet<>(), new HashMap<>());
+ }
+
+ /**
+ * Creates an object of specified class using classes from specified container.
+ *
+ * @param className specified class
+ * @param implementations for creating an object
+ * @param demanded already required dependencies
+ * @param created already created objects
+ * @return created object
+ * @throws AmbiguousImplementationException when found multiple implementations for a dependency
+ * @throws ImplementationNotFoundException if found no implementation for a dependency
+ * @throws InjectionCycleException if found a circular dependency
+ * @throws ClassNotFoundException if found not existing class
+ */
+ @NotNull
+ private static Object create(@NotNull String className, @NotNull List implementations,
+ @NotNull Set demanded,
+ @NotNull Map created) throws Exception {
+ if (demanded.contains(className)) {
+ if (created.containsKey(className)) {
+ return created.get(className);
+ } else {
+ throw new InjectionCycleException();
+ }
+ }
+ demanded.add(className);
+
+ Class> toCreate = Class.forName(className);
+ if (Modifier.isAbstract(toCreate.getModifiers()) || toCreate.isInterface()) {
+ String foundImplementation = null;
+ for (String implementation : implementations) {
+ Class> implementationClass = Class.forName(implementation);
+ if (toCreate.isAssignableFrom(implementationClass) && !toCreate.equals(implementationClass)) {
+ if (foundImplementation != null) {
+ throw new AmbiguousImplementationException();
+ } else {
+ foundImplementation = implementation;
+ }
+ }
+ }
+ if (foundImplementation == null) {
+ throw new ImplementationNotFoundException();
+ }
+ Object implementationObject = create(foundImplementation, implementations, demanded, created);
+ created.put(className, implementationObject);
+ return implementationObject;
+ }
+
+ Constructor> constructor = toCreate.getConstructors()[0];
+ Class>[] parameters = constructor.getParameterTypes();
+ ArrayList