diff --git a/diagram-klas-draw.io.png b/diagram-klas-draw.io.png deleted file mode 100644 index 45837ff..0000000 Binary files a/diagram-klas-draw.io.png and /dev/null differ diff --git a/diagram-klas-draw.io.xml b/diagram-klas-draw.io.xml deleted file mode 100644 index ae310e9..0000000 --- a/diagram-klas-draw.io.xml +++ /dev/null @@ -1 +0,0 @@ -7VxRc5s6Fv41nnEf0jHGYOcxdtPdzKS7maYzu/dRBtlWKyMvyEncX79HSMKAREKM7Nw7l06nhYMkJJ1P53znSHjgL7Yv/0jRbvONxZgOxqP4ZeB/GYzH3sQfwX9CcpCS6ehaCtYpiVWho+CR/MZKqOqt9yTGWaUgZ4xysqsKI5YkOOIVGUpT9lwttmK0+tYdWmND8Bghakr/Q2K+UdIwGB8f/BOT9Ua/2gvVAJco+rVO2T5RLxyM/VX+Rz7eIt2YGmm2QTF7Lon824G/SBnj8mr7ssBUTK6eN1nva8PTouMpTnibCkGg+sEPevA4hrlQtyzlG7ZmCaK3R+k8Hx8WLYzgbsO3FC49uISXpof/CvnnQN/+UTyLb4Rq4DYmaMvEDAnhV0J19Z+Y84NCA9pzBqJjB+4Z26lyssuin42jVqKM7dNIlVK64yhdY1VqWsw4QBmzLYb+QpEUU8TJU7V1pDC1LsqpqjAqdCgV2DGS8Kw863BRav8oynVh14vq7BOie6yRFFLo9pzAxVpc3CwznqKIP8KskWSd6QLQdFHGUG72TLYUJbiqtxVLuFa5uEeUrBO4jmA+cQqCJ5xyAuvjRj3gQhfzaENofI8ObC/mM+OAfX0337CU/IZmkX4HPE65Uu44rJR4FDUVmlKcQZkHrUqvEN2jjKsyEaMU7TKyLDq8BaWSZM44Z1tVSI9U4GvBKEvzCdCrUU+NBTNirPilJDIBop6Op6Gsoszc2J/I++ej0RhfK9mmbC9mYTOoKqh5BSK+AZGrJUniHAr+DTz5hnaAA7QVqsqRsaAoA5gs7glMZeXJXFa8S1aseKAAVL2rwQkmilehBJhkv7Ce8ITlUFuVdKBEGmIUr3gjwLIdiqBb93mZL5Oj5LuaSyF63hCOH0Eu+vQMDkmYDWhvRXNjsyFxjJPcanHEkcSMAIhapzCOYA5/wU4uhNkKYFwLuPeO9/BXFE/5giVizZEcMRgA+YwzbsXSuDWWNHbCdtAZO0DOxGJcaoqlpG4jpGK1O/RO0uoWdJF7EKXGH7lJv/IMVfumqn2LCilaYvrAMsIJE+2nsmxNtRfQniYGb2lv1l15gUV5hi8YfpIm4IlBNeUXlunRK9RcCbRAGYpttarexGzJR3GsrMdQ2xdoIr/8BBeyxap9MRqZg0cuFRmq2m2r/gttcWzUlx155ClI27d1Q6mlJ3oc77OcDdNelvT29EwrMhy1dMU65uiyJqfGmnwDaT0rOx8r83X0qZDgXRtI8GaBBQmBAyTMTFIWUfT7tzQfyi6NTEhcJWDDZCFpsSxFsojtVJm7x/y6NygnG5Rpa1g1EzQrjIJJdxRd9wTNsfZmpjuwas8BQfOsDO0VUtFE0uYZBtOcrCnmLBm2J1OZZERDTX1a1rus5bAZBRd6nrVcpePuitYWwVXurMiPgWlPBuXkmCjaNjlW5OC8z6PiXiThRp/H4UQLHnBKYMCCRuStN/rdcgbNUwMup9DU3NaScV1zatuXB2EhSk59Oq04dX9Wc9ayT6rWUYfNyTn7e8JJlTz4Ks3y9bTycCF7cGoe0Dct/xnysyOH+DsZSXqxu4NSa4sdGhb72+Eu+YkjDnatJ+tnJOvTGlm3xm1aVmHrEwds3TMDt6tMp9Nzn9mUZC/RcphbRp+EjkWF7/ruwz3sX5ebF+uxU/bUhpqJA3LumTFez8476m/actW7oOe24Gp+tPfD+pJvQdTBh1VyltUU4Y96YnD0o08Ofqy9mJphghVvoYMwITDNw/kpnFL8GSmcpmtlCuf7H0XhLCnYoyfuCdzlCNzEEoHbCVw9gjtJ7ZZ863sJXG9nW2/CuEiano2X9VlT9/q7IC/TdqTKy1Rw1Z1d6ZbyveJig7iyO3xCuzr4y9u7SRKhSNDZsJRqfWMnvrc9Z8NuS0d07YDj+eZhLK3sXUXB4f/24minctYSGqPdSx5iCIxJ+VWuLfFsUnomsHGl1CyeKWZStPnK8Q6FOy2obh/C4Jb1orZjHyDb1WUbI4BxN171TAL6rcnISxlTAcz0DhCGkgiXD4WYIV7XsK06N3XCuUFi4/ZLmp9VLi/u0rJa5TzduvhqS/sMrG0aBi0DIgekLZieKSDyZ9VTx59HM3/QsOERo2yTN1fbe1lSJnh4p8jpvSeT9bFRM5S6QOTkm6cBi03HPnS6ZOh0HVgW4cgWOjnRu7lNDfY0xSg+LOBfLhaHMIpLxihGiYX7RLLYv5c/c7smCqvrnueczHOK5dgpxrKhxncQY/nmTlkfY3XUn23Hy6Y/FzGWmSWT2etzk6R+9Z8NPZYox4aeiYtMtuMDLwVxm772tVg3RlbheafRMz11H0LP9MstkWVMnkTjCvrH4OetuLAc7Mm1myyz3d/yfvQAy5vxw5vBcD7XJ5/eHnVmuxZT+MEE2H1Qeh3U+bDl5PbU5hkdBKUTWwand41/HtdYGMJOJ7Zt8HGx+aA3il27xkHlAGcwcL3J+25fODuDLzzppGYwq6WwroOywt5bvvNJzdA/Ezl6jRs5OKnpAgHB7FJsyNzvne/Br/a7/Gf+0r2eL56YYYfv2VJVLuKOibmze0X08Vz5PVRxWLd3sCc72FlrVDQ7WCsIXHyzrrlhn3lypz/LV+tW/bn4at2zqG8uM8hVht1hM35FkljO1z4/yVluryS31CTZ7cuOkohwaUlAM5WGjteiueaUuOjB3Va21NCA1K5o5tUu9ZbskpbMkoO1rwQHkWbo+CeXPpIMdiZ+dq5e3xkLZjUW0fC11wm0PTAZZf/lT0tKaawvC16aKWUt2xN4vrEGx7Zw3dO7GJ38kYVS9h/yuDDEb4CiyWK8splpA4ELShn2lNK5/mw/hGRN2TpQn5VSyrjwCwZfCICPCM6G8lDCq+cwVTj5DYNnjE+s/JVg+u66RY9v0vV+C7OcDW9fcLTPtfupcqhCqrC3Rhe0RrateRuap++nhXB7/JVPyVuOv6Xq3/4f \ No newline at end of file diff --git a/src/main/java/myinjector/AbstractSettings.java b/src/main/java/myinjector/AbstractSettings.java index 77949a8..162d748 100644 --- a/src/main/java/myinjector/AbstractSettings.java +++ b/src/main/java/myinjector/AbstractSettings.java @@ -1,5 +1,7 @@ package myinjector; +import myinjector.Exceptions.WrongOutputClassException; + import java.util.HashMap; import java.util.LinkedList; import java.util.List; @@ -16,18 +18,21 @@ public AbstractSettings() { public abstract void load(); - protected BindingInfo addBinding(Class sourceClass, Class outputClass){ - // @TODO: check if outputClass isn't abstract or interface - BindingInfo bindingInfo = new BindingInfo(outputClass); - List bindingInfoList; - if(bindings.containsKey(sourceClass)){ - bindingInfoList = bindings.get(sourceClass); - } else { - bindingInfoList = new LinkedList(); - } - bindingInfoList.add(bindingInfo); - this.bindings.put(sourceClass, bindingInfoList); - return bindingInfo; + protected BindingInfo addBinding(Class sourceClass, Class outputClass) throws WrongOutputClassException { + if(outputClass.isInterface()){ + throw new WrongOutputClassException(String.format("Class %s cannot be created because it is " + + "an interface.", outputClass.toGenericString())); + } + BindingInfo bindingInfo = new BindingInfo(outputClass); + List bindingInfoList; + if(bindings.containsKey(sourceClass)){ + bindingInfoList = bindings.get(sourceClass); + } else { + bindingInfoList = new LinkedList(); + } + bindingInfoList.add(bindingInfo); + this.bindings.put(sourceClass, bindingInfoList); + return bindingInfo; } public BindingInfo getBindingInfo(Class sourceClass){ @@ -39,19 +44,17 @@ public BindingInfo getBindingInfo(Class sourceClass){ } public BindingInfo getNamedBindingInfo(Class sourceClass, String name){ - System.out.println("Getting named binding info for class " + sourceClass.getName() + " and string " + name); List bindingInfoList = getAllBindingInfos(sourceClass); - for (BindingInfo bindingInfo:bindingInfoList) { - System.out.println("Checking binding info: " + bindingInfo.getName()); - if(bindingInfo.getName() != null){ - if(bindingInfo.getName().equals(name)){ - System.out.println("I found binding!"); - return bindingInfo; + if(bindingInfoList != null){ + for (BindingInfo bindingInfo:bindingInfoList) { + if(bindingInfo.getBindingName() != null){ + if(bindingInfo.getBindingName().equals(name)){ + return bindingInfo; + } } } } - System.out.println("Returning null"); - return null; //@TODO replace with: display warning there is no such binding + return null; } private List getAllBindingInfos(Class sourceClass){ diff --git a/src/main/java/myinjector/Annotations/Multiple.java b/src/main/java/myinjector/Annotations/Multiple.java new file mode 100644 index 0000000..85b23e9 --- /dev/null +++ b/src/main/java/myinjector/Annotations/Multiple.java @@ -0,0 +1,9 @@ +package myinjector.Annotations; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) +public @interface Multiple { + int number(); +} diff --git a/src/main/java/myinjector/Annotations/Optional.java b/src/main/java/myinjector/Annotations/Optional.java index 1b9a26e..f07bfbf 100644 --- a/src/main/java/myinjector/Annotations/Optional.java +++ b/src/main/java/myinjector/Annotations/Optional.java @@ -5,4 +5,5 @@ @Retention(RetentionPolicy.RUNTIME) public @interface Optional { + } diff --git a/src/main/java/myinjector/BindingInfo.java b/src/main/java/myinjector/BindingInfo.java index 24920ef..b7f3974 100644 --- a/src/main/java/myinjector/BindingInfo.java +++ b/src/main/java/myinjector/BindingInfo.java @@ -1,27 +1,43 @@ package myinjector; +import myinjector.Dependencies.ClassDependencies; import myinjector.Scopes.IScope; import myinjector.Scopes.Prototype; import myinjector.Scopes.Singleton; + public class BindingInfo { private Class clazz; - private String name; + private ClassDependencies classDependencies; + private String bindingName; private IScope scope; + private Object instance; + private int number = 1; + private BindingInfo multipleBindingInfo; public BindingInfo(Class clazz){ this.clazz = clazz; - this.scope = new Prototype(); + this.scope = new Prototype(this); } public BindingInfo setSingleton(){ - this.scope = new Singleton(); + this.scope = new Singleton(this); + return this; + } + + public BindingInfo setBindingName(String bindingName){ + this.bindingName = bindingName; + return this; + } + + public BindingInfo toInstance(Object instance){ + this.instance = instance; return this; } - public BindingInfo setName(String name){ - this.name = name; + public BindingInfo setMultiple(int number){ + this.number = number; return this; } @@ -29,11 +45,35 @@ public Class getClazz() { return clazz; } - public String getName() { - return name; + public String getBindingName() { + return bindingName; } public IScope getScope() { return scope; } + + public void setClassDependencies(ClassDependencies classDependencies) { + this.classDependencies = classDependencies; + } + + public ClassDependencies getClassDependencies(){ + return classDependencies; + } + + public Object getInstance() { + return instance; + } + + public int getNumber() { + return number; + } + + public BindingInfo getMultipleBindingInfo() { + return multipleBindingInfo; + } + + public void setMultipleBindingInfo(BindingInfo multipleBindingInfo) { + this.multipleBindingInfo = multipleBindingInfo; + } } diff --git a/src/main/java/myinjector/Builder.java b/src/main/java/myinjector/Builder.java deleted file mode 100644 index 90fc30b..0000000 --- a/src/main/java/myinjector/Builder.java +++ /dev/null @@ -1,68 +0,0 @@ -package myinjector; - -import myinjector.Annotations.Inject; - -import java.lang.reflect.*; -import java.util.Arrays; -import java.util.Comparator; - -public class Builder{ - - private Injector injector; - - public Builder(AbstractSettings settings){ - this.injector = new Injector(settings); - } - - public T createInstance(Class clazz) { - System.out.println("Creating object: " + clazz.getName()); - Constructor constructor = findConstructor(clazz); - Object[] arguments = injector.injectArguments(constructor); - T outputObject = null; - try { - outputObject = (T)constructor.newInstance(arguments); - } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { - e.printStackTrace(); - } - injector.injectDependencies(outputObject); - return outputObject; - } - - - private Constructor findConstructor(Class clazz) { - Constructor[] allConstructors = clazz.getConstructors(); - if(allConstructors.length == 0){ - Constructor constructor = null; - try { - constructor = clazz.getConstructor(); - } catch (NoSuchMethodException e) { - //@TODO: display info that clazz can not be created - } - return constructor; - } - for (Constructor constructor: allConstructors) { - if(isExplicitInjectionConstructor(constructor)){ - return constructor; - } - } - - return findImplicitConstructor(allConstructors); - } - - private boolean isExplicitInjectionConstructor(Constructor constructor) - { - return (constructor.getAnnotation(Inject.class) != null); - } - - private Constructor findImplicitConstructor(Constructor[] constructors) { - Arrays.sort(constructors, new Comparator() { - public int compare(Constructor constr1, Constructor constr2){ - if(constr1.getParameterTypes().length >= constr2.getParameterTypes().length) - return -1; - else return 1; - } - }); - - return constructors[0]; - } -} diff --git a/src/main/java/myinjector/ComponentBuilder.java b/src/main/java/myinjector/ComponentBuilder.java new file mode 100644 index 0000000..b37a5d2 --- /dev/null +++ b/src/main/java/myinjector/ComponentBuilder.java @@ -0,0 +1,121 @@ +package myinjector; + +import myinjector.Dependencies.ClassDependencies; +import myinjector.Dependencies.ConstructorDependency; +import myinjector.Dependencies.FieldDependency; +import myinjector.Dependencies.MethodDependency; + +import java.lang.reflect.*; +import java.util.*; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class ComponentBuilder { + private static final Logger logger = Logger.getLogger("myinjector"); + + public T createInstance(BindingInfo bindingInfo) { + if(bindingInfo.getInstance() != null){ + return (T) bindingInfo.getInstance(); + } + + if(bindingInfo.getNumber() != 1){ + Collection collectionObject = null; + try { + collectionObject = (Collection) bindingInfo.getClazz().newInstance(); + } catch (InstantiationException | IllegalAccessException e) { + e.printStackTrace(); + } + + for(int i=0; i T buildObject(BindingInfo bindingInfo){ + logger.log(Level.INFO, "Building object: " + bindingInfo.getClazz().getSimpleName()); + ClassDependencies classDependencies = bindingInfo.getClassDependencies(); + ConstructorDependency constructorDependency = classDependencies.getConstructorDependency(); + Constructor constructor = constructorDependency.getConstructor(); + List arguments = new LinkedList<>(); + + for(BindingInfo argumentBindingInfo:constructorDependency.getArguments()){ + arguments.add(argumentBindingInfo.getScope().getInstance(this)); + } + T outputObject = null; + try { + outputObject = (T)constructor.newInstance(arguments.toArray()); + } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { + e.printStackTrace(); + } + + injectDependencies(outputObject, bindingInfo); + return outputObject; + } + + private void injectDependencies(T outputObject, BindingInfo bindingInfo) { + logger.log(Level.INFO, "Injecting dependencies for: " + bindingInfo.getClazz().getSimpleName()); + ClassDependencies classDependencies = bindingInfo.getClassDependencies(); + List methodDependencies = classDependencies.getMethodsToInject(); + injectMethods(outputObject, methodDependencies); + + List fieldDependencies = classDependencies.getFieldsToInject(); + injectFields(outputObject, fieldDependencies); + } + + private void injectMethods(T outputObject, List methodDependencies){ + for(MethodDependency methodDependency:methodDependencies){ + methodDependency.getMethod().setAccessible(true); + List arguments = new LinkedList<>(); + if(methodDependency.canInvoke()){ + for(BindingInfo argumentBindingInfo:methodDependency.getArguments()){ + if(methodDependency.isOptional()){ + try{ + arguments.add(argumentBindingInfo.getScope().getInstance(this)); + } catch (Throwable throwable){ + methodDependency.setCanInvoke(false); } + } else { + arguments.add(argumentBindingInfo.getScope().getInstance(this)); + } + } + + if(methodDependency.canInvoke()){ + try { + methodDependency.getMethod().invoke(outputObject, arguments.toArray()); + } catch (IllegalAccessException | InvocationTargetException e) { + e.printStackTrace(); + } + } + } + } + } + + private void injectFields(T outputObject, List fieldDependencies){ + for(FieldDependency fieldDependency:fieldDependencies){ + fieldDependency.getField().setAccessible(true); + Object createdObject = null; + + if(fieldDependency.canInvoke()){ + if(fieldDependency.isOptional()){ + try{ + createdObject = fieldDependency.getArgument().getScope().getInstance(this); + } catch (Throwable throwable){ + fieldDependency.setCanInvoke(false); } + } else { + createdObject = fieldDependency.getArgument().getScope().getInstance(this); + } + + if(fieldDependency.canInvoke()){ + try { + fieldDependency.getField().set(outputObject, createdObject); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + } + } + } + } +} diff --git a/src/main/java/myinjector/DefaultInjector.java b/src/main/java/myinjector/DefaultInjector.java new file mode 100644 index 0000000..e32e194 --- /dev/null +++ b/src/main/java/myinjector/DefaultInjector.java @@ -0,0 +1,188 @@ +package myinjector; + +import myinjector.Annotations.*; +import myinjector.Dependencies.*; +import myinjector.Exceptions.CycleDependencyException; + +import java.lang.reflect.*; +import java.util.*; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class DefaultInjector implements IMyInjector { + + private AbstractSettings settings; + private ComponentBuilder componentBuilder; + private static final Logger logger = Logger.getLogger("myinjector"); + + public DefaultInjector(AbstractSettings settings){ + this.settings = settings; + this.componentBuilder = new ComponentBuilder(); + logger.setLevel(Level.OFF); + System.setProperty("java.util.logging.SimpleFormatter.format", + "%1$tF %1$tT \t %5$s%6$s%n"); + } + + public void turnOnLogger(){ + logger.setLevel(Level.INFO); + } + + public void turnOffLogger(){ + logger.setLevel(Level.OFF); + } + + public T get(Class clazz){ + BindingInfo bindingInfo = checkBinding(clazz); + return bindingInfo.getScope().getInstance(componentBuilder); + } + + private BindingInfo checkBinding(Class clazz){ + BindingInfo bindingInfo = settings.getBindingInfo(clazz); + return updateBindingInfo(clazz, bindingInfo); + } + + private BindingInfo checkBinding(Class clazz, String name){ + BindingInfo bindingInfo = settings.getNamedBindingInfo(clazz, name); + return updateBindingInfo(clazz,bindingInfo); + } + + private BindingInfo updateBindingInfo(Class clazz, BindingInfo bindingInfo){ + if(bindingInfo == null){ + bindingInfo = settings.addBinding(clazz, clazz); + } + + if(!bindingInfo.getClazz().isPrimitive() + && bindingInfo.getClassDependencies() == null + && !bindingInfo.getClazz().isArray() + && !Collection.class.isAssignableFrom(bindingInfo.getClazz()) + && !String.class.isAssignableFrom(bindingInfo.getClazz())){ + resolveClassAnnotation(bindingInfo); + resolveDependencies(bindingInfo); + } + return bindingInfo; + } + + private void resolveClassAnnotation(BindingInfo bindingInfo){ + if(isAnnotatedWith(Singleton.class, bindingInfo.getClazz())){ + bindingInfo.setSingleton(); + } + } + + private void resolveDependencies(BindingInfo bindingInfo) { + ClassDependencies classDependencies = new ClassDependencies(bindingInfo.getClazz()); + bindingInfo.setClassDependencies(classDependencies); + + Constructor constructor = classDependencies.getConstructorDependency().getConstructor(); + classDependencies.getConstructorDependency().setArguments(getArguments(constructor)); + + List methodDependencyList = classDependencies.getMethodsToInject(); + for(MethodDependency methodDependency:methodDependencyList){ + if(methodDependency.isOptional()){ + try { + methodDependency.setArguments(getArguments(methodDependency.getMethod())); + } catch (Throwable throwable){ + methodDependency.setCanInvoke(false); + } + } else { + methodDependency.setArguments(getArguments(methodDependency.getMethod())); + } + } + + List fieldDependenciesList = classDependencies.getFieldsToInject(); + for(FieldDependency fieldDependency:fieldDependenciesList){ + Field field = fieldDependency.getField(); + if(fieldDependency.isOptional()){ + try { + fieldDependency.setArgument(checkAnnotationsAndReturnBinding(field)); + } catch (Throwable throwable){ + fieldDependency.setCanInvoke(false); + } + } else { + fieldDependency.setArgument(checkAnnotationsAndReturnBinding(field)); + } + } + + if(isThereCycleDependency(bindingInfo, new HashMap<>())){ + throw new CycleDependencyException("There is a cycle dependency in class " + bindingInfo.getClazz()); + } + } + + private List getArguments(Executable executable){ + List bindingInfoList = new LinkedList<>(); + for(Parameter parameter:executable.getParameters()){ + bindingInfoList.add(checkAnnotationsAndReturnBinding(parameter)); + } + return bindingInfoList; + } + + private BindingInfo checkAnnotationsAndReturnBinding(Parameter parameter){ + BindingInfo bindingInfo; + if(isAnnotatedWith(Named.class, parameter)){ + bindingInfo = checkBinding(parameter.getType(), parameter.getAnnotation(Named.class).name()); + } else { + bindingInfo = checkBinding(parameter.getType()); + } + + if(isAnnotatedWith(Multiple.class, parameter)){ + bindingInfo.setMultiple(parameter.getAnnotation(Multiple.class).number()); + Type collectionType = parameter.getParameterizedType(); + Type elementType = ((ParameterizedType) collectionType).getActualTypeArguments()[0]; + bindingInfo.setMultipleBindingInfo(checkBinding((Class)elementType)); + } + + return bindingInfo; + } + + private BindingInfo checkAnnotationsAndReturnBinding(Field field){ + BindingInfo bindingInfo; + if(isAnnotatedWith(Named.class, field)){ + bindingInfo = checkBinding(field.getType(), field.getAnnotation(Named.class).name()); + } else { + bindingInfo = checkBinding(field.getType()); + } + + if(isAnnotatedWith(Multiple.class, field)){ + bindingInfo.setMultiple(field.getAnnotation(Multiple.class).number()); + Type collectionType = field.getGenericType(); + Type elementType = ((ParameterizedType) collectionType).getActualTypeArguments()[0]; + bindingInfo.setMultipleBindingInfo(checkBinding((Class)elementType)); + } + + return bindingInfo; + } + + private boolean isAnnotatedWith(Class annotationClass, AnnotatedElement annotatedElement){ + return annotatedElement.getAnnotation(annotationClass) != null; + } + + private boolean isThereCycleDependency(BindingInfo bindingInfo, Map dependencyMap){ + bindingInfo = selectCorrectBindingInfo(bindingInfo); + + if(bindingInfo.getClassDependencies() == null){ + return false; + } + + if(dependencyMap.containsKey(bindingInfo.getClazz())){ + return true; + } else { + List argumentsList = bindingInfo.getClassDependencies().getConstructorDependency().getArguments(); + if(argumentsList == null){ + return false; + } + dependencyMap.put(bindingInfo.getClazz(), 1); + for(BindingInfo argumentBindingInfo:argumentsList){ + if(isThereCycleDependency(argumentBindingInfo, dependencyMap)){ + return true; + } + } + + return false; + } + } + + private BindingInfo selectCorrectBindingInfo(BindingInfo bindingInfo){ + return (bindingInfo.getMultipleBindingInfo() != null) ? bindingInfo.getMultipleBindingInfo() : bindingInfo; + } + + +} diff --git a/src/main/java/myinjector/Dependencies/ClassDependencies.java b/src/main/java/myinjector/Dependencies/ClassDependencies.java new file mode 100644 index 0000000..551957e --- /dev/null +++ b/src/main/java/myinjector/Dependencies/ClassDependencies.java @@ -0,0 +1,148 @@ +package myinjector.Dependencies; + + +import myinjector.Annotations.Inject; +import myinjector.Annotations.Optional; +import myinjector.Dependencies.ConstructorDependency; +import myinjector.Dependencies.FieldDependency; +import myinjector.Dependencies.MethodDependency; + +import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Comparator; +import java.util.LinkedList; +import java.util.List; + + +public class ClassDependencies { + private ConstructorDependency constructor; + private List methodsToInject; + private List fieldsToInject; + + public ClassDependencies(Class clazz){ + this.constructor = new ConstructorDependency(findConstructor(clazz)); + this.methodsToInject = new LinkedList<>(); + this.fieldsToInject = new LinkedList<>(); + findMethodsAndFields(clazz); + } + + private Constructor findConstructor(Class clazz) { + Constructor[] allConstructors = clazz.getConstructors(); + if(allConstructors.length == 0){ + Constructor constructor = null; + try { + constructor = clazz.getConstructor(); + } catch (NoSuchMethodException e) { + e.printStackTrace(); + } + return constructor; + } + for (Constructor constructor: allConstructors) { + if(isExplicitInjectionConstructor(constructor)){ + return constructor; + } + } + + return findImplicitConstructor(allConstructors); + } + + private boolean isExplicitInjectionConstructor(Constructor constructor) + { + return (constructor.getAnnotation(Inject.class) != null); + } + + private Constructor findImplicitConstructor(Constructor[] constructors) { + Arrays.sort(constructors, new Comparator() { + public int compare(Constructor constr1, Constructor constr2){ + if(constr1.getParameterTypes().length >= constr2.getParameterTypes().length) + return -1; + else return 1; + } + }); + + return constructors[0]; + } + + private void findMethodsAndFields(Class clazz) { + List classes = getAllExtendedOrImplementedTypes(clazz); + for(Class clazzFromList:classes){ + checkClassMethods(clazzFromList); + checkClassFields(clazzFromList); + } + } + + private void checkClassMethods(Class clazz){ + for(Method method : clazz.getDeclaredMethods()){ + if(isAnnotatedWithInjected(method)){ + MethodDependency foundMethod = new MethodDependency(method); + if(isAnnotatedWithOptional(method)){ + foundMethod.setOptional(true); + } + methodsToInject.add(foundMethod); + } + } + } + + private void checkClassFields(Class clazz){ + for(Field field : clazz.getDeclaredFields()){ + if(isAnnotatedWithInjected(field)){ + FieldDependency foundField = new FieldDependency(field); + if(isAnnotatedWithOptional(field)){ + foundField.setOptional(true); + } + fieldsToInject.add(foundField); + } + } + } + + private boolean isAnnotatedWithInjected(AnnotatedElement annotatedElementn){ + return annotatedElementn.getAnnotation(Inject.class) != null; + } + + private boolean isAnnotatedWithOptional(AnnotatedElement annotatedElementn){ + return annotatedElementn.getAnnotation(Optional.class) != null; + } + + public List getAllExtendedOrImplementedTypes(Class clazz) { + List result = new LinkedList<>(); + + do { + result.add(clazz); + + Class[] interfaces = clazz.getInterfaces(); + if (interfaces.length > 0) { + result.addAll(Arrays.asList(interfaces)); + + for (Class interfaze : interfaces) { + result.addAll(getAllExtendedOrImplementedTypes(interfaze)); + } + } + + Class superClass = clazz.getSuperclass(); + + if (superClass == null) { + break; + } + + clazz = superClass; + } while (!"java.lang.Object".equals(clazz.getCanonicalName())); + + return result; + } + + public List getFieldsToInject(){ + return fieldsToInject; + } + + public ConstructorDependency getConstructorDependency() { + return constructor; + } + + public List getMethodsToInject(){ + return methodsToInject; + } + +} diff --git a/src/main/java/myinjector/Dependencies/ConstructorDependency.java b/src/main/java/myinjector/Dependencies/ConstructorDependency.java new file mode 100644 index 0000000..7929af3 --- /dev/null +++ b/src/main/java/myinjector/Dependencies/ConstructorDependency.java @@ -0,0 +1,27 @@ +package myinjector.Dependencies; + +import myinjector.BindingInfo; + +import java.lang.reflect.Constructor; +import java.util.List; + +public class ConstructorDependency { + private Constructor constructor; + private List arguments; + + public ConstructorDependency(Constructor constructor){ + this.constructor = constructor; + } + + public Constructor getConstructor() { + return constructor; + } + + public List getArguments() { + return arguments; + } + + public void setArguments(List arguments) { + this.arguments = arguments; + } +} diff --git a/src/main/java/myinjector/Dependencies/DependencyFinder.java b/src/main/java/myinjector/Dependencies/DependencyFinder.java new file mode 100644 index 0000000..076372e --- /dev/null +++ b/src/main/java/myinjector/Dependencies/DependencyFinder.java @@ -0,0 +1,8 @@ +package myinjector.Dependencies; + + +import java.lang.reflect.Constructor; + +public class DependencyFinder { + +} diff --git a/src/main/java/myinjector/Dependencies/FieldDependency.java b/src/main/java/myinjector/Dependencies/FieldDependency.java new file mode 100644 index 0000000..2e6597c --- /dev/null +++ b/src/main/java/myinjector/Dependencies/FieldDependency.java @@ -0,0 +1,43 @@ +package myinjector.Dependencies; + +import myinjector.BindingInfo; +import java.lang.reflect.Field; + +public class FieldDependency { + private Field field; + private BindingInfo argument; + private boolean isOptional = false; + private boolean canInvoke = true; + + public FieldDependency(Field field) { + this.field = field; + } + + public BindingInfo getArgument() { + return argument; + } + + public void setArgument(BindingInfo argument) { + this.argument = argument; + } + + public Field getField() { + return field; + } + + public boolean isOptional() { + return isOptional; + } + + public void setOptional(boolean optional) { + isOptional = optional; + } + + public boolean canInvoke() { + return canInvoke; + } + + public void setCanInvoke(boolean canInvoke) { + this.canInvoke = canInvoke; + } +} diff --git a/src/main/java/myinjector/Dependencies/MethodDependency.java b/src/main/java/myinjector/Dependencies/MethodDependency.java new file mode 100644 index 0000000..1d091d0 --- /dev/null +++ b/src/main/java/myinjector/Dependencies/MethodDependency.java @@ -0,0 +1,45 @@ +package myinjector.Dependencies; + +import myinjector.BindingInfo; + +import java.lang.reflect.Method; +import java.util.List; + +public class MethodDependency { + private Method method; + private List arguments; + private boolean isOptional = false; + private boolean canInvoke = true; + + public MethodDependency(Method method) { + this.method = method; + } + + public List getArguments() { + return arguments; + } + + public void setArguments(List arguments) { + this.arguments = arguments; + } + + public Method getMethod() { + return method; + } + + public boolean isOptional() { + return isOptional; + } + + public void setOptional(boolean optional) { + isOptional = optional; + } + + public boolean canInvoke() { + return canInvoke; + } + + public void setCanInvoke(boolean canInvoke) { + this.canInvoke = canInvoke; + } +} diff --git a/src/main/java/myinjector/Exceptions/BindingNotFoundException.java b/src/main/java/myinjector/Exceptions/BindingNotFoundException.java deleted file mode 100644 index cc9a76c..0000000 --- a/src/main/java/myinjector/Exceptions/BindingNotFoundException.java +++ /dev/null @@ -1,7 +0,0 @@ -package myinjector.Exceptions; - -public class BindingNotFoundException extends RuntimeException { - public BindingNotFoundException(String message) { - super(message); - } -} diff --git a/src/main/java/myinjector/Exceptions/CycleDependencyException.java b/src/main/java/myinjector/Exceptions/CycleDependencyException.java new file mode 100644 index 0000000..b7fa574 --- /dev/null +++ b/src/main/java/myinjector/Exceptions/CycleDependencyException.java @@ -0,0 +1,8 @@ +package myinjector.Exceptions; + + +public class CycleDependencyException extends RuntimeException { + public CycleDependencyException(String message) { + super(message); + } +} diff --git a/src/main/java/myinjector/Exceptions/WrongOutputClassException.java b/src/main/java/myinjector/Exceptions/WrongOutputClassException.java new file mode 100644 index 0000000..9408be5 --- /dev/null +++ b/src/main/java/myinjector/Exceptions/WrongOutputClassException.java @@ -0,0 +1,8 @@ +package myinjector.Exceptions; + + +public class WrongOutputClassException extends RuntimeException{ + public WrongOutputClassException(String message) { + super(message); + } +} diff --git a/src/main/java/myinjector/IMyInjector.java b/src/main/java/myinjector/IMyInjector.java new file mode 100644 index 0000000..bb48379 --- /dev/null +++ b/src/main/java/myinjector/IMyInjector.java @@ -0,0 +1,9 @@ +package myinjector; + + +public interface IMyInjector { + T get(Class clazz); + + void turnOnLogger(); + void turnOffLogger(); +} diff --git a/src/main/java/myinjector/Injector.java b/src/main/java/myinjector/Injector.java deleted file mode 100644 index 2cef428..0000000 --- a/src/main/java/myinjector/Injector.java +++ /dev/null @@ -1,73 +0,0 @@ -package myinjector; - - -import myinjector.Annotations.Inject; -import myinjector.Annotations.Named; - -import java.lang.reflect.*; -import java.util.ArrayList; -import java.util.List; - -public class Injector { - - private Resolver resolver; - - public Injector(AbstractSettings settings){ - this.resolver = Resolver.getInstance(settings); - } - - public void injectDependencies(T object){ - System.out.println("Injecting dependencies for: " + object.getClass().getName()); - injectFieldDependencies(object); - injectMethodDependencies(object); - } - - private void injectMethodDependencies(T object) { - Method[] methods = object.getClass().getDeclaredMethods(); - for(Method method : methods){ - if(method.getAnnotation(Inject.class) != null){ - System.out.println("Found method injection: " + method.getName()); - method.setAccessible(true); - System.out.println("Checking method: " + method.getName()); - Object[] arguments = injectArguments(method); - try { - method.invoke(object,arguments); - } catch (IllegalAccessException | InvocationTargetException e) { - e.printStackTrace(); - } - - } - } - } - - private void injectFieldDependencies(T object) { - Field[] fields = object.getClass().getDeclaredFields(); - for(Field field : fields){ - if(field.getAnnotation(Inject.class) != null){ - field.setAccessible(true); - Object createdObject = resolver.resolve(field.getType()); - try { - field.set(object, createdObject); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } - } - } - } - - public Object[] injectArguments(Executable executable) { - if(executable.getParameterTypes().length > 0){ - List arguments = new ArrayList(); - for(Parameter parameter:executable.getParameters()){ - Named named = parameter.getAnnotation(Named.class); - if(named != null){ - arguments.add(resolver.resolveNamed(parameter.getType(),named.name())); - } else { - arguments.add(resolver.resolve(parameter.getType())); - } - } - return arguments.toArray(); - } - return null; - } -} diff --git a/src/main/java/myinjector/InjectorFactory.java b/src/main/java/myinjector/InjectorFactory.java new file mode 100644 index 0000000..c556bfe --- /dev/null +++ b/src/main/java/myinjector/InjectorFactory.java @@ -0,0 +1,17 @@ +package myinjector; + + +public class InjectorFactory { + public static IMyInjector getInjector(String name, AbstractSettings settings){ + + if(name.equalsIgnoreCase("DefaultInjector")){ + return new DefaultInjector(settings); + } + + if(name.equalsIgnoreCase("SecondInjector")){ + return new DefaultInjector(settings); + } + + return new DefaultInjector(settings); + } +} diff --git a/src/main/java/myinjector/MyInjector.java b/src/main/java/myinjector/MyInjector.java deleted file mode 100644 index 630b4f0..0000000 --- a/src/main/java/myinjector/MyInjector.java +++ /dev/null @@ -1,18 +0,0 @@ -package myinjector; - -public class MyInjector { - - private AbstractSettings settings; - private Resolver resolver; - - public MyInjector(AbstractSettings settings){ - this.settings = settings; - this.resolver = Resolver.getInstance(settings); - } - - public T get(Class clazz){ - System.out.println("Someone wants to create " + clazz.getName()); - return resolver.resolve(clazz); - } - -} diff --git a/src/main/java/myinjector/Resolver.java b/src/main/java/myinjector/Resolver.java deleted file mode 100644 index f7bb78b..0000000 --- a/src/main/java/myinjector/Resolver.java +++ /dev/null @@ -1,52 +0,0 @@ -package myinjector; - - -import myinjector.Annotations.Singleton; - -import java.lang.annotation.Annotation; - -class Resolver { - - private static Resolver instance = null; - private AbstractSettings settings; - - private Resolver(AbstractSettings settings){ - this.settings = settings; - } - - static Resolver getInstance(AbstractSettings settings) { - if(instance == null) { - instance = new Resolver(settings); - } - //return instance; - return new Resolver(settings); - } - - T resolve(Class clazz){ - System.out.println("resolving class " + clazz.getName()); - BindingInfo bindingInfo = settings.getBindingInfo(clazz); - return checkBindingInfoAndStartBulding(clazz, bindingInfo); - } - - public T resolveNamed(Class clazz, String name){ - System.out.println("resolving named class " + clazz.getName()); - BindingInfo bindingInfo = settings.getNamedBindingInfo(clazz, name); - return checkBindingInfoAndStartBulding(clazz,bindingInfo); - } - - public T checkBindingInfoAndStartBulding(Class clazz, BindingInfo bindingInfo){ - if(bindingInfo == null){ - System.out.println("I didnt find binding for " + clazz.getName()); - bindingInfo = settings.addBinding(clazz, clazz); - resolveClassAnnotation(bindingInfo); - } - System.out.println("Scope for this class is: " + bindingInfo.getScope().getClass().getName()); - return bindingInfo.getScope().getInstance(bindingInfo.getClazz(), settings); - } - - private void resolveClassAnnotation(BindingInfo bindingInfo){ - if(bindingInfo.getClazz().getAnnotation(Singleton.class) != null){ - bindingInfo.setSingleton(); - } - } -} diff --git a/src/main/java/myinjector/Scopes/IScope.java b/src/main/java/myinjector/Scopes/IScope.java index 3cde047..d145b62 100644 --- a/src/main/java/myinjector/Scopes/IScope.java +++ b/src/main/java/myinjector/Scopes/IScope.java @@ -1,8 +1,7 @@ package myinjector.Scopes; - -import myinjector.AbstractSettings; +import myinjector.ComponentBuilder; public interface IScope { - public T getInstance(Class clazz, AbstractSettings settings); + T getInstance(ComponentBuilder componentBuilder); } diff --git a/src/main/java/myinjector/Scopes/Prototype.java b/src/main/java/myinjector/Scopes/Prototype.java index ed2aac6..9a167ad 100644 --- a/src/main/java/myinjector/Scopes/Prototype.java +++ b/src/main/java/myinjector/Scopes/Prototype.java @@ -1,13 +1,17 @@ package myinjector.Scopes; - -import myinjector.AbstractSettings; -import myinjector.Builder; +import myinjector.BindingInfo; +import myinjector.ComponentBuilder; public class Prototype implements IScope{ - public T getInstance(Class clazz, AbstractSettings settings) { - System.out.println("Prototype called for class " + clazz.getName()); - return new Builder(settings).createInstance(clazz); + private BindingInfo bindingInfo; + + public Prototype(BindingInfo bindingInfo){ + this.bindingInfo = bindingInfo; + } + + public T getInstance(ComponentBuilder componentBuilder) { + return componentBuilder.createInstance(bindingInfo); } } diff --git a/src/main/java/myinjector/Scopes/Singleton.java b/src/main/java/myinjector/Scopes/Singleton.java index 48bd407..e041642 100644 --- a/src/main/java/myinjector/Scopes/Singleton.java +++ b/src/main/java/myinjector/Scopes/Singleton.java @@ -1,20 +1,31 @@ package myinjector.Scopes; -import myinjector.AbstractSettings; -import myinjector.Builder; +import myinjector.BindingInfo; +import myinjector.ComponentBuilder; + +import java.util.logging.Level; +import java.util.logging.Logger; public class Singleton implements IScope{ private boolean alreadyCreated = false; private Object createdObject; + private BindingInfo bindingInfo; + private static final Logger logger = Logger.getLogger("myinjector"); + + + public Singleton(BindingInfo bindingInfo){ + this.bindingInfo = bindingInfo; + } - public T getInstance(Class clazz, AbstractSettings settings) { + public T getInstance(ComponentBuilder componentBuilder) { if(alreadyCreated){ + logger.log(Level.INFO, "Singleton object " + createdObject.getClass().getSimpleName() + " already created."); return (T) createdObject; } else { alreadyCreated = true; - createdObject = new Builder(settings).createInstance(clazz); + createdObject = componentBuilder.createInstance(bindingInfo); return (T) createdObject; } } diff --git a/src/test/java/AnnotatedSingletonTest/AnnotatedSingleton.java b/src/test/java/AnnotatedSingletonTest/AnnotatedSingleton.java index ceaeb61..8436ba3 100644 --- a/src/test/java/AnnotatedSingletonTest/AnnotatedSingleton.java +++ b/src/test/java/AnnotatedSingletonTest/AnnotatedSingleton.java @@ -1,6 +1,7 @@ package AnnotatedSingletonTest; -import myinjector.MyInjector; +import myinjector.IMyInjector; +import myinjector.InjectorFactory; import org.junit.Test; import static org.junit.Assert.assertSame; @@ -8,7 +9,7 @@ public class AnnotatedSingleton { @Test public void getOneSwordTwoTimes(){ - MyInjector myInjector = new MyInjector(new BindingService()); + IMyInjector myInjector = InjectorFactory.getInjector("DefaultInjector", new BindingService()); Sword sword1 = myInjector.get(Sword.class); Sword sword2 = myInjector.get(Sword.class); assertSame(sword1, sword2); diff --git a/src/test/java/AnnotatedSingletonTest/BindingService.java b/src/test/java/AnnotatedSingletonTest/BindingService.java index 4827237..1953550 100644 --- a/src/test/java/AnnotatedSingletonTest/BindingService.java +++ b/src/test/java/AnnotatedSingletonTest/BindingService.java @@ -6,6 +6,6 @@ public class BindingService extends AbstractSettings { public void load() { - + addBinding(Sword.class, Sword.class); } } diff --git a/src/test/java/ComplexTest1/Airport.java b/src/test/java/ComplexTest1/Airport.java new file mode 100644 index 0000000..da1b823 --- /dev/null +++ b/src/test/java/ComplexTest1/Airport.java @@ -0,0 +1,39 @@ +package ComplexTest1; + + +import myinjector.Annotations.Inject; +import myinjector.Annotations.Named; + +public class Airport { + private String name; + private int capacity; + private Plane firstPlane; + private Plane secondPlane; + + public Airport(@Named(name = "AO") String name, @Named(name = "Boeing 123")Plane firstPlane, @Named(name = "Boeing 797") Plane secondPlane){ + this.name = name; + this.firstPlane = firstPlane; + this.secondPlane = secondPlane; + } + + public String getName() { + return name; + } + + public Plane getFirstPlane() { + return firstPlane; + } + + public Plane getSecondPlane() { + return secondPlane; + } + + public int getCapacity() { + return capacity; + } + + @Inject + public void setCapacity(@Named(name = "capacity1") int capacity) { + this.capacity = capacity; + } +} diff --git a/src/test/java/ComplexTest1/BindingService.java b/src/test/java/ComplexTest1/BindingService.java new file mode 100644 index 0000000..19a64d0 --- /dev/null +++ b/src/test/java/ComplexTest1/BindingService.java @@ -0,0 +1,14 @@ +package ComplexTest1; + + +import myinjector.AbstractSettings; + +public class BindingService extends AbstractSettings { + + public void load() { + addBinding(Plane.class, Boeing123.class).setBindingName("Boeing 123"); + addBinding(Plane.class, Boeing797.class).setBindingName("Boeing 797"); + addBinding(String.class, String.class).setBindingName("AO").toInstance("Aiport One"); + addBinding(int.class, int.class).setBindingName("capacity1").toInstance(2); + } +} diff --git a/src/test/java/ComplexTest1/Boeing123.java b/src/test/java/ComplexTest1/Boeing123.java new file mode 100644 index 0000000..66c0b6e --- /dev/null +++ b/src/test/java/ComplexTest1/Boeing123.java @@ -0,0 +1,8 @@ +package ComplexTest1; + +public class Boeing123 extends Plane{ + @Override + public void fly() { + System.out.println("Boeing123 flying"); + } +} diff --git a/src/test/java/ComplexTest1/Boeing797.java b/src/test/java/ComplexTest1/Boeing797.java new file mode 100644 index 0000000..3ae7d6a --- /dev/null +++ b/src/test/java/ComplexTest1/Boeing797.java @@ -0,0 +1,9 @@ +package ComplexTest1; + + +public class Boeing797 extends Plane { + @Override + public void fly() { + System.out.println("Bowing797 flying."); + } +} diff --git a/src/test/java/ComplexTest1/ComplexTest.java b/src/test/java/ComplexTest1/ComplexTest.java new file mode 100644 index 0000000..7cb9f16 --- /dev/null +++ b/src/test/java/ComplexTest1/ComplexTest.java @@ -0,0 +1,34 @@ +package ComplexTest1; + +import myinjector.IMyInjector; +import myinjector.InjectorFactory; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.LinkedList; + +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertThat; + +public class ComplexTest { + @Test + public void complexTest(){ + IMyInjector myInjector = InjectorFactory.getInjector("DefaultInjector", new BindingService()); + Airport airport = myInjector.get(Airport.class); + assertThat(airport, instanceOf(Airport.class)); + Plane boeing123 = airport.getFirstPlane(); + Pilot firstPilot = boeing123.getPilot(); + assertThat(firstPilot, instanceOf(Pilot.class)); + Plane boeing797 = airport.getSecondPlane(); + Pilot secondPilot = boeing797.getPilot(); + assertSame(firstPilot, secondPilot); + ArrayList crewMembers = boeing123.getCrewMembers(); + assertEquals(crewMembers.size(), 10); + assertThat(crewMembers.get(9), instanceOf(CrewMember.class)); + LinkedList passengers = boeing123.getPassengers(); + assertEquals(passengers.size(), 100); + assertThat(passengers.get(99), instanceOf(Passenger.class)); + } +} diff --git a/src/test/java/ComplexTest1/CrewMember.java b/src/test/java/ComplexTest1/CrewMember.java new file mode 100644 index 0000000..bcff13b --- /dev/null +++ b/src/test/java/ComplexTest1/CrewMember.java @@ -0,0 +1,5 @@ +package ComplexTest1; + + +public class CrewMember { +} diff --git a/src/test/java/ComplexTest1/Passenger.java b/src/test/java/ComplexTest1/Passenger.java new file mode 100644 index 0000000..6e93546 --- /dev/null +++ b/src/test/java/ComplexTest1/Passenger.java @@ -0,0 +1,4 @@ +package ComplexTest1; + +public class Passenger { +} diff --git a/src/test/java/ComplexTest1/Pilot.java b/src/test/java/ComplexTest1/Pilot.java new file mode 100644 index 0000000..5fda254 --- /dev/null +++ b/src/test/java/ComplexTest1/Pilot.java @@ -0,0 +1,7 @@ +package ComplexTest1; + +import myinjector.Annotations.Singleton; + +@Singleton +public class Pilot extends CrewMember { +} diff --git a/src/test/java/ComplexTest1/Plane.java b/src/test/java/ComplexTest1/Plane.java new file mode 100644 index 0000000..e320fcc --- /dev/null +++ b/src/test/java/ComplexTest1/Plane.java @@ -0,0 +1,44 @@ +package ComplexTest1; + +import myinjector.Annotations.Inject; +import myinjector.Annotations.Multiple; + +import java.util.ArrayList; +import java.util.LinkedList; + + +public abstract class Plane { + + @Inject + private Wings wings; + @Inject + @Multiple(number = 10) + private ArrayList crewMembers; + @Inject + @Multiple(number = 100) + private LinkedList passengers; + private Pilot pilot; + + public abstract void fly(); + + @Inject + public void setPilot(Pilot pilot) { + this.pilot = pilot; + } + + public Pilot getPilot() { + return pilot; + } + + public Wings getWings() { + return wings; + } + + public ArrayList getCrewMembers() { + return crewMembers; + } + + public LinkedList getPassengers() { + return passengers; + } +} diff --git a/src/test/java/ComplexTest1/Wing.java b/src/test/java/ComplexTest1/Wing.java new file mode 100644 index 0000000..3cd767f --- /dev/null +++ b/src/test/java/ComplexTest1/Wing.java @@ -0,0 +1,5 @@ +package ComplexTest1; + + +public class Wing { +} diff --git a/src/test/java/ComplexTest1/Wings.java b/src/test/java/ComplexTest1/Wings.java new file mode 100644 index 0000000..fa5a402 --- /dev/null +++ b/src/test/java/ComplexTest1/Wings.java @@ -0,0 +1,18 @@ +package ComplexTest1; + + +import myinjector.Annotations.Multiple; + +import java.util.ArrayList; + +public class Wings { + private ArrayList wings; + + public ArrayList getWings() { + return wings; + } + + public void setWings(@Multiple(number = 2) ArrayList wings) { + this.wings = wings; + } +} diff --git a/src/test/java/CyclicDependencies/BindingService.java b/src/test/java/CyclicDependencies/BindingService.java new file mode 100644 index 0000000..2a906d3 --- /dev/null +++ b/src/test/java/CyclicDependencies/BindingService.java @@ -0,0 +1,11 @@ +package CyclicDependencies; + +import myinjector.AbstractSettings; + + +public class BindingService extends AbstractSettings { + + public void load() { + + } +} diff --git a/src/test/java/CyclicDependencies/CyclicDependencies.java b/src/test/java/CyclicDependencies/CyclicDependencies.java new file mode 100644 index 0000000..e8a5b7c --- /dev/null +++ b/src/test/java/CyclicDependencies/CyclicDependencies.java @@ -0,0 +1,15 @@ +package CyclicDependencies; + + +import myinjector.Exceptions.CycleDependencyException; +import myinjector.IMyInjector; +import myinjector.InjectorFactory; +import org.junit.Test; + +public class CyclicDependencies { + @Test(expected = CycleDependencyException.class) + public void testCyclicDependency(){ + IMyInjector myInjector = InjectorFactory.getInjector("DeafultInjector", new BindingService()); + Home home = myInjector.get(Home.class); + } +} diff --git a/src/test/java/CyclicDependencies/Home.java b/src/test/java/CyclicDependencies/Home.java new file mode 100644 index 0000000..5d0a511 --- /dev/null +++ b/src/test/java/CyclicDependencies/Home.java @@ -0,0 +1,15 @@ +package CyclicDependencies; + + +public class Home { + + private Person person; + + public Home(Person person){ + this.person = person; + } + + public Person getPerson() { + return person; + } +} diff --git a/src/test/java/CyclicDependencies/Person.java b/src/test/java/CyclicDependencies/Person.java new file mode 100644 index 0000000..9f8e355 --- /dev/null +++ b/src/test/java/CyclicDependencies/Person.java @@ -0,0 +1,14 @@ +package CyclicDependencies; + + +public class Person { + private Home home; + + public Person(Home home){ + this.home = home; + } + + public Home getHome() { + return home; + } +} diff --git a/src/test/java/CyclicDependencyInMethodsAndFields/BindingService.java b/src/test/java/CyclicDependencyInMethodsAndFields/BindingService.java new file mode 100644 index 0000000..29de3a0 --- /dev/null +++ b/src/test/java/CyclicDependencyInMethodsAndFields/BindingService.java @@ -0,0 +1,11 @@ +package CyclicDependencyInMethodsAndFields; + +import myinjector.AbstractSettings; + + +public class BindingService extends AbstractSettings { + + public void load() { + + } +} diff --git a/src/test/java/CyclicDependencyInMethodsAndFields/Computer.java b/src/test/java/CyclicDependencyInMethodsAndFields/Computer.java new file mode 100644 index 0000000..222582b --- /dev/null +++ b/src/test/java/CyclicDependencyInMethodsAndFields/Computer.java @@ -0,0 +1,12 @@ +package CyclicDependencyInMethodsAndFields; + +import myinjector.Annotations.Inject; + +public class Computer { + ImportantPart importantPart; + + @Inject + public void setImportantPart(ImportantPart importantPart){ + this.importantPart = importantPart; + } +} diff --git a/src/test/java/CyclicDependencyInMethodsAndFields/ImportantPart.java b/src/test/java/CyclicDependencyInMethodsAndFields/ImportantPart.java new file mode 100644 index 0000000..23db7b2 --- /dev/null +++ b/src/test/java/CyclicDependencyInMethodsAndFields/ImportantPart.java @@ -0,0 +1,9 @@ +package CyclicDependencyInMethodsAndFields; + +import myinjector.Annotations.Inject; + +public class ImportantPart { + @Inject + Computer computer; + +} diff --git a/src/test/java/CyclicDependencyInMethodsAndFields/MethodFieldCyclicDependencies.java b/src/test/java/CyclicDependencyInMethodsAndFields/MethodFieldCyclicDependencies.java new file mode 100644 index 0000000..5e24e9a --- /dev/null +++ b/src/test/java/CyclicDependencyInMethodsAndFields/MethodFieldCyclicDependencies.java @@ -0,0 +1,17 @@ +package CyclicDependencyInMethodsAndFields; + +import myinjector.IMyInjector; +import myinjector.InjectorFactory; +import org.junit.Test; + +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.MatcherAssert.assertThat; + +public class MethodFieldCyclicDependencies { + @Test(expected = StackOverflowError.class) + public void testCyclicDependency(){ + IMyInjector myInjector = InjectorFactory.getInjector("", new BindingService()); + Computer computer = myInjector.get(Computer.class); + assertThat(computer, instanceOf(Computer.class)); + } +} diff --git a/src/test/java/DefinedSingletonTest/DefinedSingleton.java b/src/test/java/DefinedSingletonTest/DefinedSingleton.java index 5a5f575..0b9bfea 100644 --- a/src/test/java/DefinedSingletonTest/DefinedSingleton.java +++ b/src/test/java/DefinedSingletonTest/DefinedSingleton.java @@ -2,7 +2,8 @@ import Common.IWeapon; -import myinjector.MyInjector; +import myinjector.IMyInjector; +import myinjector.InjectorFactory; import org.junit.Test; import static org.junit.Assert.assertSame; @@ -10,7 +11,7 @@ public class DefinedSingleton { @Test public void getSingletonSword(){ - MyInjector myInjector = new MyInjector(new BindingService()); + IMyInjector myInjector = InjectorFactory.getInjector("DefaultInjector", new BindingService()); Sword sword1 = myInjector.get(IWeapon.class); Sword sword2 = myInjector.get(IWeapon.class); assertSame(sword1, sword2); diff --git a/src/test/java/FieldDependencyInjectionTest/FieldDependencyInjection.java b/src/test/java/FieldDependencyInjectionTest/FieldDependencyInjection.java index b69a15d..ba271ae 100644 --- a/src/test/java/FieldDependencyInjectionTest/FieldDependencyInjection.java +++ b/src/test/java/FieldDependencyInjectionTest/FieldDependencyInjection.java @@ -1,7 +1,8 @@ package FieldDependencyInjectionTest; import Common.Warrior; -import myinjector.MyInjector; +import myinjector.IMyInjector; +import myinjector.InjectorFactory; import org.junit.Test; import static org.hamcrest.CoreMatchers.instanceOf; @@ -10,7 +11,7 @@ public class FieldDependencyInjection { @Test public void getWarriorWithGunAndSilencer() { - MyInjector myInjector = new MyInjector(new BindingService()); + IMyInjector myInjector = InjectorFactory.getInjector("DefaultInjector", new BindingService()); Warrior warrior = myInjector.get(Warrior.class); Gun gun = (Gun) warrior.getWeapon(); assertThat(warrior.getWeapon(), instanceOf(Gun.class)); diff --git a/src/test/java/MethodDependencyInjectionTest/Gun.java b/src/test/java/MethodDependencyInjectionTest/Gun.java index 6a1dc41..60fd2a7 100644 --- a/src/test/java/MethodDependencyInjectionTest/Gun.java +++ b/src/test/java/MethodDependencyInjectionTest/Gun.java @@ -7,7 +7,6 @@ public class Gun implements IWeapon { private GunSilencer gunSilencer; - @Inject public Gun(){ } diff --git a/src/test/java/MethodDependencyInjectionTest/MethodDependencyInjection.java b/src/test/java/MethodDependencyInjectionTest/MethodDependencyInjection.java index 13c46c3..a4bb573 100644 --- a/src/test/java/MethodDependencyInjectionTest/MethodDependencyInjection.java +++ b/src/test/java/MethodDependencyInjectionTest/MethodDependencyInjection.java @@ -1,7 +1,8 @@ package MethodDependencyInjectionTest; import Common.Warrior; -import myinjector.MyInjector; +import myinjector.IMyInjector; +import myinjector.InjectorFactory; import org.junit.Test; import static org.hamcrest.CoreMatchers.instanceOf; @@ -10,7 +11,7 @@ public class MethodDependencyInjection { @Test public void getWarriorWithGunAndSilencer(){ - MyInjector myInjector = new MyInjector(new BindingService()); + IMyInjector myInjector = InjectorFactory.getInjector("DefaultInjector", new BindingService()); Warrior warrior = myInjector.get(Warrior.class); Gun gun = (Gun) warrior.getWeapon(); assertThat(warrior.getWeapon(), instanceOf(Gun.class)); diff --git a/src/test/java/MultiThreadTest/Airport.java b/src/test/java/MultiThreadTest/Airport.java new file mode 100644 index 0000000..aa77cfc --- /dev/null +++ b/src/test/java/MultiThreadTest/Airport.java @@ -0,0 +1,39 @@ +package MultiThreadTest; + + +import myinjector.Annotations.Inject; +import myinjector.Annotations.Named; + +public class Airport { + private String name; + private int capacity; + private Plane firstPlane; + private Plane secondPlane; + + public Airport(@Named(name = "AO") String name, @Named(name = "Boeing 123") Plane firstPlane, @Named(name = "Boeing 797") Plane secondPlane){ + this.name = name; + this.firstPlane = firstPlane; + this.secondPlane = secondPlane; + } + + public String getName() { + return name; + } + + public Plane getFirstPlane() { + return firstPlane; + } + + public Plane getSecondPlane() { + return secondPlane; + } + + public int getCapacity() { + return capacity; + } + + @Inject + public void setCapacity(@Named(name = "capacity1") int capacity) { + this.capacity = capacity; + } +} diff --git a/src/test/java/MultiThreadTest/BindingService.java b/src/test/java/MultiThreadTest/BindingService.java new file mode 100644 index 0000000..43d4359 --- /dev/null +++ b/src/test/java/MultiThreadTest/BindingService.java @@ -0,0 +1,14 @@ +package MultiThreadTest; + + +import myinjector.AbstractSettings; + +public class BindingService extends AbstractSettings { + + public void load() { + addBinding(Plane.class, Boeing123.class).setBindingName("Boeing 123"); + addBinding(Plane.class, Boeing797.class).setBindingName("Boeing 797"); + addBinding(String.class, String.class).setBindingName("AO").toInstance("Aiport One"); + addBinding(int.class, int.class).setBindingName("capacity1").toInstance(2); + } +} diff --git a/src/test/java/MultiThreadTest/Boeing123.java b/src/test/java/MultiThreadTest/Boeing123.java new file mode 100644 index 0000000..f846b64 --- /dev/null +++ b/src/test/java/MultiThreadTest/Boeing123.java @@ -0,0 +1,8 @@ +package MultiThreadTest; + +public class Boeing123 extends Plane { + @Override + public void fly() { + System.out.println("Boeing123 flying"); + } +} diff --git a/src/test/java/MultiThreadTest/Boeing797.java b/src/test/java/MultiThreadTest/Boeing797.java new file mode 100644 index 0000000..5d45142 --- /dev/null +++ b/src/test/java/MultiThreadTest/Boeing797.java @@ -0,0 +1,9 @@ +package MultiThreadTest; + + +public class Boeing797 extends Plane { + @Override + public void fly() { + System.out.println("Bowing797 flying."); + } +} diff --git a/src/test/java/MultiThreadTest/BuildAirportThread.java b/src/test/java/MultiThreadTest/BuildAirportThread.java new file mode 100644 index 0000000..f6d3cd9 --- /dev/null +++ b/src/test/java/MultiThreadTest/BuildAirportThread.java @@ -0,0 +1,21 @@ +package MultiThreadTest; + + +import myinjector.IMyInjector; + +public class BuildAirportThread extends Thread { + IMyInjector myInjector; + private Airport airport = null; + + public BuildAirportThread(IMyInjector myInjector){ + this.myInjector = myInjector; + } + + public void run(){ + airport = myInjector.get(Airport.class); + } + + public Airport getAirport() { + return airport; + } +} diff --git a/src/test/java/MultiThreadTest/CrewMember.java b/src/test/java/MultiThreadTest/CrewMember.java new file mode 100644 index 0000000..646badb --- /dev/null +++ b/src/test/java/MultiThreadTest/CrewMember.java @@ -0,0 +1,5 @@ +package MultiThreadTest; + + +public class CrewMember { +} diff --git a/src/test/java/MultiThreadTest/MultiThreadTest.java b/src/test/java/MultiThreadTest/MultiThreadTest.java new file mode 100644 index 0000000..4879878 --- /dev/null +++ b/src/test/java/MultiThreadTest/MultiThreadTest.java @@ -0,0 +1,72 @@ +package MultiThreadTest; + +import myinjector.IMyInjector; +import myinjector.InjectorFactory; +import org.junit.Before; +import org.junit.Test; + +import java.util.ArrayList; + +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.junit.Assert.*; + +public class MultiThreadTest { + Airport airport1; + Airport airport2; + BuildAirportThread thread1; + BuildAirportThread thread2; + + @Before + public void multiThread(){ + IMyInjector myInjector = InjectorFactory.getInjector("DefaultInjector", new BindingService()); + myInjector.turnOnLogger(); + BuildAirportThread thread1 = new BuildAirportThread(myInjector); + BuildAirportThread thread2 = new BuildAirportThread(myInjector); + thread1.start(); + thread2.start(); + try { + thread1.join(); + thread2.join(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + + } + + @Test + public void testAirport1(){ + airport1 = thread1.getAirport(); + assertThat(airport1, instanceOf(Airport.class)); + } + + @Test + public void testAirport2(){ + airport2 = thread2.getAirport(); + assertThat(airport2, instanceOf(Airport.class)); + } + + @Test + public void testOtherThings(){ + Plane boeing123_1 = airport1.getFirstPlane(); + Plane boeing123_2 = airport2.getFirstPlane(); + Pilot firstPilot_1 = boeing123_1.getPilot(); + Pilot firstPilot_2 = boeing123_2.getPilot(); + assertThat(firstPilot_1, instanceOf(Pilot.class)); + assertThat(firstPilot_2, instanceOf(Pilot.class)); + Plane boeing797_1 = airport1.getSecondPlane(); + Plane boeing797_2 = airport2.getSecondPlane(); + Pilot secondPilot_1 = boeing797_1.getPilot(); + Pilot secondPilot_2 = boeing797_2.getPilot(); + assertSame(firstPilot_1, secondPilot_1); + assertSame(firstPilot_2, secondPilot_2); + assertNotEquals(firstPilot_1, firstPilot_2); + ArrayList crewMembers_1 = boeing123_1.getCrewMembers(); + ArrayList crewMembers_2 = boeing123_2.getCrewMembers(); + assertEquals(crewMembers_1.size(), 10); + assertEquals(crewMembers_2.size(), 10); + assertThat(crewMembers_1.get(9), instanceOf(CrewMember.class)); + assertThat(crewMembers_2.get(9), instanceOf(CrewMember.class)); + } + +} diff --git a/src/test/java/MultiThreadTest/Passenger.java b/src/test/java/MultiThreadTest/Passenger.java new file mode 100644 index 0000000..d44b22a --- /dev/null +++ b/src/test/java/MultiThreadTest/Passenger.java @@ -0,0 +1,4 @@ +package MultiThreadTest; + +public class Passenger { +} diff --git a/src/test/java/MultiThreadTest/Pilot.java b/src/test/java/MultiThreadTest/Pilot.java new file mode 100644 index 0000000..0060cbb --- /dev/null +++ b/src/test/java/MultiThreadTest/Pilot.java @@ -0,0 +1,7 @@ +package MultiThreadTest; + +import myinjector.Annotations.Singleton; + +@Singleton +public class Pilot extends CrewMember { +} diff --git a/src/test/java/MultiThreadTest/Plane.java b/src/test/java/MultiThreadTest/Plane.java new file mode 100644 index 0000000..d069e26 --- /dev/null +++ b/src/test/java/MultiThreadTest/Plane.java @@ -0,0 +1,44 @@ +package MultiThreadTest; + +import myinjector.Annotations.Inject; +import myinjector.Annotations.Multiple; + +import java.util.ArrayList; +import java.util.LinkedList; + + +public abstract class Plane { + + @Inject + private Wings wings; + @Inject + @Multiple(number = 10) + private ArrayList crewMembers; + @Inject + @Multiple(number = 100) + private LinkedList passengers; + private Pilot pilot; + + public abstract void fly(); + + @Inject + public void setPilot(Pilot pilot) { + this.pilot = pilot; + } + + public Pilot getPilot() { + return pilot; + } + + public Wings getWings() { + return wings; + } + + public ArrayList getCrewMembers() { + return crewMembers; + } + + public LinkedList getPassengers() { + return passengers; + } +} diff --git a/src/test/java/MultiThreadTest/Wing.java b/src/test/java/MultiThreadTest/Wing.java new file mode 100644 index 0000000..e65217f --- /dev/null +++ b/src/test/java/MultiThreadTest/Wing.java @@ -0,0 +1,5 @@ +package MultiThreadTest; + + +public class Wing { +} diff --git a/src/test/java/MultiThreadTest/Wings.java b/src/test/java/MultiThreadTest/Wings.java new file mode 100644 index 0000000..b758ac1 --- /dev/null +++ b/src/test/java/MultiThreadTest/Wings.java @@ -0,0 +1,18 @@ +package MultiThreadTest; + + +import myinjector.Annotations.Multiple; + +import java.util.ArrayList; + +public class Wings { + private ArrayList wings; + + public ArrayList getWings() { + return wings; + } + + public void setWings(@Multiple(number = 2) ArrayList wings) { + this.wings = wings; + } +} diff --git a/src/test/java/MultipleTest/BindingService.java b/src/test/java/MultipleTest/BindingService.java new file mode 100644 index 0000000..ce5ebae --- /dev/null +++ b/src/test/java/MultipleTest/BindingService.java @@ -0,0 +1,10 @@ +package MultipleTest; + +import myinjector.AbstractSettings; + +public class BindingService extends AbstractSettings { + + public void load() { + addBinding(Car.class, Car.class); + } +} diff --git a/src/test/java/MultipleTest/Car.java b/src/test/java/MultipleTest/Car.java new file mode 100644 index 0000000..0c09b07 --- /dev/null +++ b/src/test/java/MultipleTest/Car.java @@ -0,0 +1,20 @@ +package MultipleTest; + +import myinjector.Annotations.Inject; +import myinjector.Annotations.Multiple; + +import java.util.LinkedList; +import java.util.List; + +public class Car { + private List tires; + + @Inject + public Car(@Multiple(number=4)LinkedList tires){ + this.tires = tires; + } + + public List getTires() { + return tires; + } +} diff --git a/src/test/java/MultipleTest/MultipleTest.java b/src/test/java/MultipleTest/MultipleTest.java new file mode 100644 index 0000000..38b164a --- /dev/null +++ b/src/test/java/MultipleTest/MultipleTest.java @@ -0,0 +1,22 @@ +package MultipleTest; + + +import myinjector.IMyInjector; +import myinjector.InjectorFactory; +import org.junit.Test; + +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.junit.Assert.assertThat; + +public class MultipleTest { + + @Test + public void testMultiple(){ + IMyInjector myInjector = InjectorFactory.getInjector("DefaultInjector", new BindingService()); + Car car = myInjector.get(Car.class); + assertThat(car.getTires().get(0), instanceOf(Tire.class)); + assertThat(car.getTires().get(1), instanceOf(Tire.class)); + assertThat(car.getTires().get(2), instanceOf(Tire.class)); + assertThat(car.getTires().get(3), instanceOf(Tire.class)); + } +} diff --git a/src/test/java/MultipleTest/Tire.java b/src/test/java/MultipleTest/Tire.java new file mode 100644 index 0000000..30ef844 --- /dev/null +++ b/src/test/java/MultipleTest/Tire.java @@ -0,0 +1,9 @@ +package MultipleTest; + + +public class Tire { + + public Tire(){ + + } +} diff --git a/src/test/java/NamedBindingTest/BindingService.java b/src/test/java/NamedBindingTest/BindingService.java index 482437f..f83728b 100644 --- a/src/test/java/NamedBindingTest/BindingService.java +++ b/src/test/java/NamedBindingTest/BindingService.java @@ -8,6 +8,6 @@ public class BindingService extends AbstractSettings { public void load() { addBinding(IWeapon.class, Sword.class); - addBinding(IWeapon.class, Katana.class).setName("Katana"); + addBinding(IWeapon.class, Katana.class).setBindingName("Katana"); } } diff --git a/src/test/java/NamedBindingTest/NamedBinding.java b/src/test/java/NamedBindingTest/NamedBinding.java index 7c8d783..7eb8b4e 100644 --- a/src/test/java/NamedBindingTest/NamedBinding.java +++ b/src/test/java/NamedBindingTest/NamedBinding.java @@ -1,7 +1,8 @@ package NamedBindingTest; -import myinjector.MyInjector; +import myinjector.IMyInjector; +import myinjector.InjectorFactory; import org.junit.Test; import static org.hamcrest.CoreMatchers.instanceOf; @@ -10,7 +11,7 @@ public class NamedBinding { @Test public void getNamedBindingKatana(){ - MyInjector myInjector = new MyInjector(new BindingService()); + IMyInjector myInjector = InjectorFactory.getInjector("DefaultInjector", new BindingService()); Warrior warrior = myInjector.get(Warrior.class); assertThat(warrior.getWeapon(), instanceOf(Katana.class)); } diff --git a/src/test/java/NoBindingsTest/NoBindings.java b/src/test/java/NoBindingsTest/NoBindings.java index 5957dd2..cdd69ff 100644 --- a/src/test/java/NoBindingsTest/NoBindings.java +++ b/src/test/java/NoBindingsTest/NoBindings.java @@ -1,6 +1,7 @@ package NoBindingsTest; -import myinjector.MyInjector; +import myinjector.IMyInjector; +import myinjector.InjectorFactory; import org.junit.Test; import static org.hamcrest.CoreMatchers.instanceOf; @@ -10,7 +11,7 @@ public class NoBindings { @Test public void testGetSword(){ - MyInjector myInjector = new MyInjector(new BindingService()); + IMyInjector myInjector = InjectorFactory.getInjector("DefaultInjector", new BindingService()); Sword sword = myInjector.get(Sword.class); assertThat(sword, instanceOf(Sword.class)); } diff --git a/src/test/java/OptionalAnnotationTest/BindingService.java b/src/test/java/OptionalAnnotationTest/BindingService.java new file mode 100644 index 0000000..4b58074 --- /dev/null +++ b/src/test/java/OptionalAnnotationTest/BindingService.java @@ -0,0 +1,11 @@ +package OptionalAnnotationTest; + +import myinjector.AbstractSettings; + + +public class BindingService extends AbstractSettings { + + public void load() { + + } +} diff --git a/src/test/java/OptionalAnnotationTest/OptionalAnnotation.java b/src/test/java/OptionalAnnotationTest/OptionalAnnotation.java new file mode 100644 index 0000000..7d22437 --- /dev/null +++ b/src/test/java/OptionalAnnotationTest/OptionalAnnotation.java @@ -0,0 +1,18 @@ +package OptionalAnnotationTest; + +import myinjector.IMyInjector; +import myinjector.InjectorFactory; +import org.junit.Test; + +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.junit.Assert.assertThat; + +public class OptionalAnnotation { + + @Test + public void testGetSword(){ + IMyInjector myInjector = InjectorFactory.getInjector("DefaultInjector", new BindingService()); + Sword sword = myInjector.get(Sword.class); + assertThat(sword, instanceOf(Sword.class)); + } +} diff --git a/src/test/java/OptionalAnnotationTest/Sword.java b/src/test/java/OptionalAnnotationTest/Sword.java new file mode 100644 index 0000000..a5cf782 --- /dev/null +++ b/src/test/java/OptionalAnnotationTest/Sword.java @@ -0,0 +1,23 @@ +package OptionalAnnotationTest; + +import Common.IWeapon; +import myinjector.Annotations.Inject; +import myinjector.Annotations.Optional; + +public class Sword implements IWeapon { + + public String swordName; + + public Sword(){ + + } + public void hit(String target){ + System.out.println(String.format("Cut %s in half", target)); + } + + @Inject + @Optional + public void setSwordName(String name){ + this.swordName = name; + } +} diff --git a/src/test/java/OptionalMethodWithInterfaceArgumentTest/BindingService.java b/src/test/java/OptionalMethodWithInterfaceArgumentTest/BindingService.java new file mode 100644 index 0000000..cf45d0a --- /dev/null +++ b/src/test/java/OptionalMethodWithInterfaceArgumentTest/BindingService.java @@ -0,0 +1,11 @@ +package OptionalMethodWithInterfaceArgumentTest; + +import myinjector.AbstractSettings; + + +public class BindingService extends AbstractSettings { + + public void load() { + + } +} diff --git a/src/test/java/OptionalMethodWithInterfaceArgumentTest/ISwordName.java b/src/test/java/OptionalMethodWithInterfaceArgumentTest/ISwordName.java new file mode 100644 index 0000000..e8d642c --- /dev/null +++ b/src/test/java/OptionalMethodWithInterfaceArgumentTest/ISwordName.java @@ -0,0 +1,5 @@ +package OptionalMethodWithInterfaceArgumentTest; + + +public interface ISwordName { +} diff --git a/src/test/java/OptionalMethodWithInterfaceArgumentTest/OptionalMethodWithInterfaceAsArgument.java b/src/test/java/OptionalMethodWithInterfaceArgumentTest/OptionalMethodWithInterfaceAsArgument.java new file mode 100644 index 0000000..3216d5c --- /dev/null +++ b/src/test/java/OptionalMethodWithInterfaceArgumentTest/OptionalMethodWithInterfaceAsArgument.java @@ -0,0 +1,18 @@ +package OptionalMethodWithInterfaceArgumentTest; + +import myinjector.IMyInjector; +import myinjector.InjectorFactory; +import org.junit.Test; + +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.junit.Assert.assertThat; + +public class OptionalMethodWithInterfaceAsArgument { + + @Test + public void testGetSword(){ + IMyInjector myInjector = InjectorFactory.getInjector("DefaultInjector", new BindingService()); + Sword sword = myInjector.get(Sword.class); + assertThat(sword, instanceOf(Sword.class)); + } +} diff --git a/src/test/java/OptionalMethodWithInterfaceArgumentTest/Sword.java b/src/test/java/OptionalMethodWithInterfaceArgumentTest/Sword.java new file mode 100644 index 0000000..7cbd205 --- /dev/null +++ b/src/test/java/OptionalMethodWithInterfaceArgumentTest/Sword.java @@ -0,0 +1,23 @@ +package OptionalMethodWithInterfaceArgumentTest; + +import Common.IWeapon; +import myinjector.Annotations.Inject; +import myinjector.Annotations.Optional; + +public class Sword implements IWeapon { + + public ISwordName swordName; + + public Sword(){ + + } + public void hit(String target){ + System.out.println(String.format("Cut %s in half", target)); + } + + @Inject + @Optional + public void setSwordName(ISwordName name){ + this.swordName = name; + } +} diff --git a/src/test/java/PrimitiveAsArgumentTest/BestDriver.java b/src/test/java/PrimitiveAsArgumentTest/BestDriver.java new file mode 100644 index 0000000..1ebb584 --- /dev/null +++ b/src/test/java/PrimitiveAsArgumentTest/BestDriver.java @@ -0,0 +1,9 @@ +package PrimitiveAsArgumentTest; + + +public class BestDriver implements IDriver { + @Override + public void connect(String url) { + System.out.println("Connected to " + url); + } +} diff --git a/src/test/java/PrimitiveAsArgumentTest/BindingService.java b/src/test/java/PrimitiveAsArgumentTest/BindingService.java new file mode 100644 index 0000000..f0547e1 --- /dev/null +++ b/src/test/java/PrimitiveAsArgumentTest/BindingService.java @@ -0,0 +1,13 @@ +package PrimitiveAsArgumentTest; + +import myinjector.AbstractSettings; + + +public class BindingService extends AbstractSettings { + + public void load() { + addBinding(DatabaseConnector.class, DatabaseConnector.class); + addBinding(IDriver.class, BestDriver.class); + addBinding(String.class, String.class).setBindingName("URL").toInstance("url://myurl"); + } +} diff --git a/src/test/java/PrimitiveAsArgumentTest/DatabaseConnector.java b/src/test/java/PrimitiveAsArgumentTest/DatabaseConnector.java new file mode 100644 index 0000000..45e3558 --- /dev/null +++ b/src/test/java/PrimitiveAsArgumentTest/DatabaseConnector.java @@ -0,0 +1,14 @@ +package PrimitiveAsArgumentTest; + + +import myinjector.Annotations.Named; + +public class DatabaseConnector { + private final IDriver driver; + private String url; + + public DatabaseConnector(@Named(name = "URL") String url, IDriver driver){ + this.url = url; + this.driver = driver; + } +} diff --git a/src/test/java/PrimitiveAsArgumentTest/IDriver.java b/src/test/java/PrimitiveAsArgumentTest/IDriver.java new file mode 100644 index 0000000..a93789e --- /dev/null +++ b/src/test/java/PrimitiveAsArgumentTest/IDriver.java @@ -0,0 +1,6 @@ +package PrimitiveAsArgumentTest; + + +public interface IDriver { + public void connect(String url); +} diff --git a/src/test/java/PrimitiveAsArgumentTest/PrimitiveAsArgument.java b/src/test/java/PrimitiveAsArgumentTest/PrimitiveAsArgument.java new file mode 100644 index 0000000..3a3c0da --- /dev/null +++ b/src/test/java/PrimitiveAsArgumentTest/PrimitiveAsArgument.java @@ -0,0 +1,18 @@ +package PrimitiveAsArgumentTest; + + +import myinjector.IMyInjector; +import myinjector.InjectorFactory; +import org.junit.Test; + +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.junit.Assert.assertThat; + +public class PrimitiveAsArgument { + @Test + public void testStringAsArgument(){ + IMyInjector myInjector = InjectorFactory.getInjector("DefaultInjector", new BindingService()); + DatabaseConnector databaseConnector = myInjector.get(DatabaseConnector.class); + assertThat(databaseConnector, instanceOf(DatabaseConnector.class)); + } +} diff --git a/src/test/java/SimpleBindingTest/SimpleBinding.java b/src/test/java/SimpleBindingTest/SimpleBinding.java index c306b72..6329ae4 100644 --- a/src/test/java/SimpleBindingTest/SimpleBinding.java +++ b/src/test/java/SimpleBindingTest/SimpleBinding.java @@ -1,7 +1,8 @@ package SimpleBindingTest; import Common.IWeapon; -import myinjector.MyInjector; +import myinjector.IMyInjector; +import myinjector.InjectorFactory; import org.junit.Test; import static org.hamcrest.CoreMatchers.instanceOf; @@ -11,7 +12,7 @@ public class SimpleBinding { @Test public void getIWeapon(){ - MyInjector myInjector = new MyInjector(new BindingService()); + IMyInjector myInjector = InjectorFactory.getInjector("DefaultInjector", new BindingService()); Sword sword = myInjector.get(IWeapon.class); assertThat(sword, instanceOf(Sword.class)); } diff --git a/src/test/java/SimpleConstructorDependencyInjectionTest/SimpleConstructorDependencyInjection.java b/src/test/java/SimpleConstructorDependencyInjectionTest/SimpleConstructorDependencyInjection.java index 4304400..d03eb55 100644 --- a/src/test/java/SimpleConstructorDependencyInjectionTest/SimpleConstructorDependencyInjection.java +++ b/src/test/java/SimpleConstructorDependencyInjectionTest/SimpleConstructorDependencyInjection.java @@ -1,7 +1,8 @@ package SimpleConstructorDependencyInjectionTest; import Common.Warrior; -import myinjector.MyInjector; +import myinjector.IMyInjector; +import myinjector.InjectorFactory; import org.junit.Test; import static org.hamcrest.CoreMatchers.instanceOf; @@ -11,7 +12,7 @@ public class SimpleConstructorDependencyInjection { @Test public void constructorDependencyInjection(){ - MyInjector myInjector = new MyInjector(new BindingService()); + IMyInjector myInjector = InjectorFactory.getInjector("DefaultInjector", new BindingService()); Warrior warrior = myInjector.get(Warrior.class); assertThat(warrior.getWeapon(), instanceOf(Sword.class)); } diff --git a/src/test/java/TwoLevelDependencyInjectionTest/TwoLevelDependencyInjection.java b/src/test/java/TwoLevelDependencyInjectionTest/TwoLevelDependencyInjection.java index 5e34852..1fdd77b 100644 --- a/src/test/java/TwoLevelDependencyInjectionTest/TwoLevelDependencyInjection.java +++ b/src/test/java/TwoLevelDependencyInjectionTest/TwoLevelDependencyInjection.java @@ -3,7 +3,8 @@ import Common.Warrior; import Common.WarriorHouse; -import myinjector.MyInjector; +import myinjector.IMyInjector; +import myinjector.InjectorFactory; import org.junit.Test; import static org.hamcrest.CoreMatchers.instanceOf; @@ -12,7 +13,7 @@ public class TwoLevelDependencyInjection { @Test public void twoLevelDependencyInjection(){ - MyInjector myInjector = new MyInjector(new BindingService()); + IMyInjector myInjector = InjectorFactory.getInjector("DefaultInjector", new BindingService()); WarriorHouse warriorHouse = myInjector.get(WarriorHouse.class); assertThat(warriorHouse.getWarrior(), instanceOf(Warrior.class)); assertThat(warriorHouse.getWarrior().getWeapon(), instanceOf(Sword.class));