]> git.somenet.org - pub/jan/dst18.git/blob - ass2-di/src/main/java/dst/ass2/di/impl/InjectionControllerImpl.java
[2.2.1] Standalone DI works now.
[pub/jan/dst18.git] / ass2-di / src / main / java / dst / ass2 / di / impl / InjectionControllerImpl.java
1 package dst.ass2.di.impl;
2
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;
9
10 import java.lang.reflect.Field;
11 import java.lang.reflect.InvocationTargetException;
12 import java.util.Map;
13 import java.util.concurrent.ConcurrentHashMap;
14 import java.util.concurrent.atomic.AtomicLong;
15
16 public class InjectionControllerImpl implements IInjectionController {
17     private final Map<Class<?>, Object> singletons = new ConcurrentHashMap<>();
18     private final AtomicLong ids = new AtomicLong(0L);
19
20
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.
24         }
25
26         boolean idPresent = false;
27         for (Field f : clazz.getDeclaredFields()) {
28
29             // handle @ComponentID
30             if (f.isAnnotationPresent(ComponentId.class)) {
31                 idPresent = true;
32                 if (f.getType() != Long.class) {
33                     throw new InjectionException(f.getName() + " is of wrong type");
34                 }
35
36                 boolean accessible = f.isAccessible();
37                 f.setAccessible(true);
38                 if (id == null) {
39                     id = ids.getAndIncrement();
40                 }
41                 f.set(obj, id);
42                 f.setAccessible(accessible);
43             }
44
45             // handle @Inject
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();
50                 }
51                 if (!fieldType.isAnnotationPresent(Component.class)) {
52                     continue;
53                 }
54
55                 Object fieldObject = singletons.get(fieldType);
56
57                 if (fieldObject == null) {
58                     try {
59                         try {
60                             fieldObject = fieldType.getConstructor(Inject.class).newInstance(f.getAnnotation(Inject.class));
61                         } catch (InvocationTargetException | NoSuchMethodException e) {
62                             fieldObject = fieldType.newInstance();
63                         }
64                     } catch (InstantiationException e) {
65                         e.printStackTrace();
66                     }
67                     initialize(fieldObject);
68                 }
69
70                 boolean accessible = f.isAccessible();
71                 f.setAccessible(true);
72                 try {
73                     f.set(obj, fieldObject);
74                 } catch (IllegalAccessException | IllegalArgumentException e) {
75                     if (f.getAnnotation(Inject.class).required()) {
76                         throw new InjectionException(e);
77                     }
78                 }
79                 f.setAccessible(accessible);
80             }
81         }
82
83         if (!idPresent) {
84             throw new InjectionException(clazz + " has no @ComponentID");
85         }
86
87         initializeClass(obj, clazz.getSuperclass(), id);
88     }
89
90
91     @Override
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");
95         }
96         if (singletons.get(obj.getClass()) != null) {
97             throw new InjectionException(obj.getClass() + " singleton already initialized");
98         }
99
100         try {
101             initializeClass(obj, obj.getClass(), null);
102         } catch (IllegalAccessException e) {
103             throw new InjectionException(e);
104         }
105
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);
109         }
110     }
111
112     @Override
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");
116         }
117         if (clazz.getAnnotation(Component.class).scope().equals(Scope.PROTOTYPE)) {
118             throw new InjectionException(clazz + " is not a SINGLETON");
119         }
120
121         T single = (T) singletons.get(clazz);
122         if (single == null) {
123             try {
124                 single = (T) clazz.newInstance();
125             } catch (InstantiationException | IllegalAccessException e) {
126                 e.printStackTrace();
127             }
128             initialize(single);
129         }
130         return single;
131     }
132 }