From 2a04d1995b5ba6e24487ccb7ef68f5d978cb256b Mon Sep 17 00:00:00 2001 From: Jan Vales Date: Wed, 9 May 2018 03:05:37 +0200 Subject: [PATCH] [2.2.1] Standalone DI works now. --- .../ass2/di/InjectionControllerFactory.java | 13 +- .../ass2/di/impl/InjectionControllerImpl.java | 132 ++++++++++++++++++ 2 files changed, 140 insertions(+), 5 deletions(-) create mode 100644 ass2-di/src/main/java/dst/ass2/di/impl/InjectionControllerImpl.java diff --git a/ass2-di/src/main/java/dst/ass2/di/InjectionControllerFactory.java b/ass2-di/src/main/java/dst/ass2/di/InjectionControllerFactory.java index 64bbf96..f20b258 100644 --- a/ass2-di/src/main/java/dst/ass2/di/InjectionControllerFactory.java +++ b/ass2-di/src/main/java/dst/ass2/di/InjectionControllerFactory.java @@ -1,10 +1,12 @@ package dst.ass2.di; +import dst.ass2.di.impl.InjectionControllerImpl; + /** * Creates and provides {@link IInjectionController} instances. */ public class InjectionControllerFactory { - + private static IInjectionController standalone = null; /** * Returns the singleton {@link IInjectionController} instance.
@@ -13,8 +15,10 @@ public class InjectionControllerFactory { * @return the instance */ public static synchronized IInjectionController getStandAloneInstance() { - // TODO - return null; + if (standalone == null) { + standalone = getNewStandaloneInstance(); + } + return standalone; } /** @@ -35,8 +39,7 @@ public class InjectionControllerFactory { * @return the newly created instance */ public static IInjectionController getNewStandaloneInstance() { - // TODO - return null; + return new InjectionControllerImpl(); } /** diff --git a/ass2-di/src/main/java/dst/ass2/di/impl/InjectionControllerImpl.java b/ass2-di/src/main/java/dst/ass2/di/impl/InjectionControllerImpl.java new file mode 100644 index 0000000..18a2072 --- /dev/null +++ b/ass2-di/src/main/java/dst/ass2/di/impl/InjectionControllerImpl.java @@ -0,0 +1,132 @@ +package dst.ass2.di.impl; + +import dst.ass2.di.IInjectionController; +import dst.ass2.di.InjectionException; +import dst.ass2.di.annotation.Component; +import dst.ass2.di.annotation.ComponentId; +import dst.ass2.di.annotation.Inject; +import dst.ass2.di.annotation.Scope; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicLong; + +public class InjectionControllerImpl implements IInjectionController { + private final Map, Object> singletons = new ConcurrentHashMap<>(); + private final AtomicLong ids = new AtomicLong(0L); + + + private void initializeClass(Object obj, Class clazz, Long id) throws IllegalAccessException { + if (clazz == null || !clazz.isAnnotationPresent(Component.class)) { + return; // nothing to be done here. + } + + boolean idPresent = false; + for (Field f : clazz.getDeclaredFields()) { + + // handle @ComponentID + if (f.isAnnotationPresent(ComponentId.class)) { + idPresent = true; + if (f.getType() != Long.class) { + throw new InjectionException(f.getName() + " is of wrong type"); + } + + boolean accessible = f.isAccessible(); + f.setAccessible(true); + if (id == null) { + id = ids.getAndIncrement(); + } + f.set(obj, id); + f.setAccessible(accessible); + } + + // handle @Inject + if (f.isAnnotationPresent(Inject.class)) { + Class fieldType = f.getType(); + if (f.getAnnotation(Inject.class).specificType() != Void.class) { + fieldType = f.getAnnotation(Inject.class).specificType(); + } + if (!fieldType.isAnnotationPresent(Component.class)) { + continue; + } + + Object fieldObject = singletons.get(fieldType); + + if (fieldObject == null) { + try { + try { + fieldObject = fieldType.getConstructor(Inject.class).newInstance(f.getAnnotation(Inject.class)); + } catch (InvocationTargetException | NoSuchMethodException e) { + fieldObject = fieldType.newInstance(); + } + } catch (InstantiationException e) { + e.printStackTrace(); + } + initialize(fieldObject); + } + + boolean accessible = f.isAccessible(); + f.setAccessible(true); + try { + f.set(obj, fieldObject); + } catch (IllegalAccessException | IllegalArgumentException e) { + if (f.getAnnotation(Inject.class).required()) { + throw new InjectionException(e); + } + } + f.setAccessible(accessible); + } + } + + if (!idPresent) { + throw new InjectionException(clazz + " has no @ComponentID"); + } + + initializeClass(obj, clazz.getSuperclass(), id); + } + + + @Override + public void initialize(Object obj) throws InjectionException { + if (!obj.getClass().isAnnotationPresent(Component.class)) { + throw new InjectionException(obj.getClass() + " isn't annotated with: @Component"); + } + if (singletons.get(obj.getClass()) != null) { + throw new InjectionException(obj.getClass() + " singleton already initialized"); + } + + try { + initializeClass(obj, obj.getClass(), null); + } catch (IllegalAccessException e) { + throw new InjectionException(e); + } + + // add singleton to singleton map, if singleton. + if (obj.getClass().getAnnotation(Component.class).scope().equals(Scope.SINGLETON)) { + singletons.put(obj.getClass(), obj); + } + } + + @Override + public T getSingletonInstance(Class clazz) throws InjectionException { + if (!clazz.isAnnotationPresent(Component.class)) { + throw new InjectionException(clazz + " isn't annotated with: @Component"); + } + if (clazz.getAnnotation(Component.class).scope().equals(Scope.PROTOTYPE)) { + throw new InjectionException(clazz + " is not a SINGLETON"); + } + + T single = (T) singletons.get(clazz); + if (single == null) { + try { + single = (T) clazz.newInstance(); + } catch (InstantiationException | IllegalAccessException e) { + e.printStackTrace(); + } + initialize(single); + } + return single; + } +} -- 2.43.0