1 package dst.ass2.di.impl;
3 import dst.ass2.di.IInjectionController;
4 import dst.ass2.di.InjectionException;
5 import dst.ass2.di.annotation.Component;
6 import dst.ass2.di.annotation.ComponentId;
7 import dst.ass2.di.annotation.Inject;
8 import dst.ass2.di.annotation.Scope;
10 import java.lang.reflect.Field;
11 import java.lang.reflect.InvocationTargetException;
13 import java.util.concurrent.ConcurrentHashMap;
14 import java.util.concurrent.atomic.AtomicLong;
16 public class InjectionControllerImpl implements IInjectionController {
17 private final Map<Class<?>, Object> singletons = new ConcurrentHashMap<>();
18 private final AtomicLong ids = new AtomicLong(0L);
21 private void initializeClass(Object obj, Class<?> clazz, Long id) throws IllegalAccessException {
22 if (clazz == null || !clazz.isAnnotationPresent(Component.class)) {
23 return; // nothing to be done here.
26 boolean idPresent = false;
27 for (Field f : clazz.getDeclaredFields()) {
29 // handle @ComponentID
30 if (f.isAnnotationPresent(ComponentId.class)) {
32 if (f.getType() != Long.class) {
33 throw new InjectionException(f.getName() + " is of wrong type");
36 boolean accessible = f.isAccessible();
37 f.setAccessible(true);
39 id = ids.getAndIncrement();
42 f.setAccessible(accessible);
46 if (f.isAnnotationPresent(Inject.class)) {
47 Class<?> fieldType = f.getType();
48 if (f.getAnnotation(Inject.class).specificType() != Void.class) {
49 fieldType = f.getAnnotation(Inject.class).specificType();
51 if (!fieldType.isAnnotationPresent(Component.class)) {
55 Object fieldObject = singletons.get(fieldType);
57 if (fieldObject == null) {
60 fieldObject = fieldType.getConstructor(Inject.class).newInstance(f.getAnnotation(Inject.class));
61 } catch (InvocationTargetException | NoSuchMethodException e) {
62 fieldObject = fieldType.newInstance();
64 } catch (InstantiationException e) {
67 initialize(fieldObject);
70 boolean accessible = f.isAccessible();
71 f.setAccessible(true);
73 f.set(obj, fieldObject);
74 } catch (IllegalAccessException | IllegalArgumentException e) {
75 if (f.getAnnotation(Inject.class).required()) {
76 throw new InjectionException(e);
79 f.setAccessible(accessible);
84 throw new InjectionException(clazz + " has no @ComponentID");
87 initializeClass(obj, clazz.getSuperclass(), id);
92 public void initialize(Object obj) throws InjectionException {
93 if (!obj.getClass().isAnnotationPresent(Component.class)) {
94 throw new InjectionException(obj.getClass() + " isn't annotated with: @Component");
96 if (singletons.get(obj.getClass()) != null) {
97 throw new InjectionException(obj.getClass() + " singleton already initialized");
101 initializeClass(obj, obj.getClass(), null);
102 } catch (IllegalAccessException e) {
103 throw new InjectionException(e);
106 // add singleton to singleton map, if singleton.
107 if (obj.getClass().getAnnotation(Component.class).scope().equals(Scope.SINGLETON)) {
108 singletons.put(obj.getClass(), obj);
113 public <T> T getSingletonInstance(Class<T> clazz) throws InjectionException {
114 if (!clazz.isAnnotationPresent(Component.class)) {
115 throw new InjectionException(clazz + " isn't annotated with: @Component");
117 if (clazz.getAnnotation(Component.class).scope().equals(Scope.PROTOTYPE)) {
118 throw new InjectionException(clazz + " is not a SINGLETON");
121 T single = (T) singletons.get(clazz);
122 if (single == null) {
124 single = (T) clazz.newInstance();
125 } catch (InstantiationException | IllegalAccessException e) {