[2.2.1] Standalone DI works now.
authorJan Vales <jan@jvales.net>
Wed, 9 May 2018 01:05:37 +0000 (03:05 +0200)
committerJan Vales <jan@jvales.net>
Wed, 9 May 2018 01:05:37 +0000 (03:05 +0200)
ass2-di/src/main/java/dst/ass2/di/InjectionControllerFactory.java
ass2-di/src/main/java/dst/ass2/di/impl/InjectionControllerImpl.java [new file with mode: 0644]

index 64bbf96b373646e73aa6b94b39a1389e54f65afb..f20b258c4ee19eb4c51d18de517093c9b2cd70b8 100644 (file)
@@ -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.<br/>
@@ -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 (file)
index 0000000..18a2072
--- /dev/null
@@ -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<Class<?>, 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> T getSingletonInstance(Class<T> 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;
+    }
+}