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);
19 private final boolean isTransparent;
21 public InjectionControllerImpl(boolean b) {
25 private void initializeClass(Object obj, Class<?> clazz, Long id) throws IllegalAccessException {
26 if (clazz == null || !clazz.isAnnotationPresent(Component.class)) {
27 return; // nothing to be done here.
30 boolean idPresent = false;
31 for (Field f : clazz.getDeclaredFields()) {
33 // handle @ComponentID
34 if (f.isAnnotationPresent(ComponentId.class)) {
36 if (f.getType() != Long.class) {
37 throw new InjectionException(f.getName() + " is of wrong type");
40 boolean accessible = f.isAccessible();
41 f.setAccessible(true);
43 id = ids.getAndIncrement();
46 f.setAccessible(accessible);
50 if (f.isAnnotationPresent(Inject.class)) {
51 Class<?> fieldType = f.getType();
52 if (f.getAnnotation(Inject.class).specificType() != Void.class) {
53 fieldType = f.getAnnotation(Inject.class).specificType();
55 if (!fieldType.isAnnotationPresent(Component.class)) {
59 Object fieldObject = singletons.get(fieldType);
61 if (fieldObject == null) {
64 fieldObject = fieldType.getConstructor(Inject.class).newInstance(f.getAnnotation(Inject.class));
65 } catch (InvocationTargetException | NoSuchMethodException e) {
66 fieldObject = fieldType.newInstance();
68 } catch (InstantiationException e) {
71 // only do this in standalone mode.
73 initialize(fieldObject);
77 boolean accessible = f.isAccessible();
78 f.setAccessible(true);
80 f.set(obj, fieldObject);
81 } catch (IllegalAccessException | IllegalArgumentException e) {
82 if (f.getAnnotation(Inject.class).required()) {
83 throw new InjectionException(e);
86 f.setAccessible(accessible);
91 throw new InjectionException(clazz + " has no @ComponentID");
94 // only do this in standalone mode.
95 if (!isTransparent) initializeClass(obj, clazz.getSuperclass(), id);
100 public void initialize(Object obj) throws InjectionException {
101 if (!obj.getClass().isAnnotationPresent(Component.class)) {
102 throw new InjectionException(obj.getClass() + " isn't annotated with: @Component");
104 if (singletons.get(obj.getClass()) != null) {
105 throw new InjectionException(obj.getClass() + " singleton already initialized");
109 initializeClass(obj, obj.getClass(), null);
110 } catch (IllegalAccessException e) {
111 throw new InjectionException(e);
114 // add singleton to singleton map, if singleton.
115 if (obj.getClass().getAnnotation(Component.class).scope().equals(Scope.SINGLETON)) {
116 singletons.put(obj.getClass(), obj);
121 public <T> T getSingletonInstance(Class<T> clazz) throws InjectionException {
122 if (!clazz.isAnnotationPresent(Component.class)) {
123 throw new InjectionException(clazz + " isn't annotated with: @Component");
125 if (clazz.getAnnotation(Component.class).scope().equals(Scope.PROTOTYPE)) {
126 throw new InjectionException(clazz + " is not a SINGLETON");
129 T single = (T) singletons.get(clazz);
130 if (single == null) {
132 single = (T) clazz.newInstance();
133 } catch (InstantiationException | IllegalAccessException e) {
137 // only do this in standalone mode.
138 if (!isTransparent) {