1 | |
|
2 | |
|
3 | |
|
4 | |
|
5 | |
|
6 | |
|
7 | |
|
8 | |
|
9 | |
|
10 | |
|
11 | |
|
12 | |
|
13 | |
|
14 | |
|
15 | |
|
16 | |
|
17 | |
package org.apache.commons.inject.impl; |
18 | |
|
19 | |
import java.lang.annotation.Annotation; |
20 | |
import java.lang.reflect.Array; |
21 | |
import java.lang.reflect.Constructor; |
22 | |
import java.lang.reflect.Field; |
23 | |
import java.lang.reflect.Method; |
24 | |
import java.lang.reflect.Modifier; |
25 | |
import java.lang.reflect.ParameterizedType; |
26 | |
import java.lang.reflect.Type; |
27 | |
import java.util.ArrayList; |
28 | |
import java.util.List; |
29 | |
|
30 | |
import javax.inject.Inject; |
31 | |
import javax.inject.Named; |
32 | |
import javax.inject.Provider; |
33 | |
|
34 | |
import org.apache.commons.inject.api.IBinding; |
35 | |
import org.apache.commons.inject.api.IInjector; |
36 | |
import org.apache.commons.inject.api.IKey; |
37 | |
import org.apache.commons.inject.api.IPoint; |
38 | |
import org.apache.commons.inject.api.IProvider; |
39 | |
import org.apache.commons.inject.api.Key; |
40 | |
import org.apache.commons.inject.impl.bind.DefaultBinding; |
41 | |
import org.apache.commons.inject.util.Generics; |
42 | |
|
43 | |
public class Introspector { |
44 | 1 | private static final Introspector introspector = new Introspector(); |
45 | 1 | private static final Class<Object> PROVIDER_CLASS = Generics.cast(Provider.class); |
46 | |
|
47 | |
|
48 | 1 | private Introspector() { |
49 | 1 | } |
50 | |
|
51 | |
public static Introspector getInstance() { |
52 | 64 | return introspector; |
53 | |
} |
54 | |
|
55 | |
public <T> AbstractBaseProvider<T> getProvider(Class<T> pType, IPoint<T> pPoint, IMutableBindingSource pBindings) { |
56 | |
@SuppressWarnings("unchecked") |
57 | 28 | final Constructor<T>[] constructors = (Constructor<T>[]) pType.getDeclaredConstructors(); |
58 | 52 | for (Constructor<T> constructor : constructors) { |
59 | 36 | if (constructor.isAnnotationPresent(Inject.class)) { |
60 | 12 | return getProvider(constructor, pBindings); |
61 | |
} |
62 | |
} |
63 | 16 | return new DefaultProvider<T>(pType, pPoint); |
64 | |
} |
65 | |
|
66 | |
public <T> AbstractBaseProvider<T> getProvider(Constructor<? extends T> pConstructor, IMutableBindingSource pBindings) { |
67 | |
@SuppressWarnings("unchecked") |
68 | 12 | final Class<Object>[] parameterClasses = (Class<Object>[]) pConstructor.getParameterTypes(); |
69 | 12 | final Type[] parameterTypes = pConstructor.getGenericParameterTypes(); |
70 | 12 | final Annotation[][] parameterAnnotations = pConstructor.getParameterAnnotations(); |
71 | 12 | final IBinding<Object>[] parameterBindings = getBindings(parameterClasses, parameterTypes, |
72 | |
parameterAnnotations, pBindings, |
73 | |
"Required to invoke the constructor " + pConstructor); |
74 | |
@SuppressWarnings("unchecked") |
75 | 12 | final Constructor<T> constructor = (Constructor<T>) pConstructor; |
76 | 12 | return new FactoryMethodProvider<T>(constructor, |
77 | |
getPoint(constructor.getDeclaringClass(), pBindings), |
78 | |
parameterBindings); |
79 | |
} |
80 | |
|
81 | |
public <T> AbstractBaseProvider<T> getProvider(Method pMethod, IMutableBindingSource pBindings) { |
82 | |
@SuppressWarnings("unchecked") |
83 | 0 | final Class<Object>[] parameterClasses = (Class<Object>[]) pMethod.getParameterTypes(); |
84 | 0 | final Type[] parameterTypes = pMethod.getGenericParameterTypes(); |
85 | 0 | final Annotation[][] parameterAnnotations = pMethod.getParameterAnnotations(); |
86 | 0 | final IBinding<Object>[] parameterBindings = getBindings(parameterClasses, parameterTypes, parameterAnnotations, pBindings, |
87 | |
"Required to invoke the method " + pMethod); |
88 | |
@SuppressWarnings("unchecked") |
89 | 0 | final Class<T> cl = (Class<T>) pMethod.getReturnType(); |
90 | 0 | final IPoint<T> point = getPoint(cl, pBindings); |
91 | 0 | return new FactoryMethodProvider<T>(pMethod, parameterBindings, point); |
92 | |
} |
93 | |
|
94 | |
private IBinding<Object>[] getBindings(Class<Object>[] pParameterClasses, Type[] pParameterTypes, Annotation[][] pParameterAnnotations, IMutableBindingSource pBindings, |
95 | |
String pCause) { |
96 | |
@SuppressWarnings("unchecked") |
97 | 120 | final IBinding<Object>[] bindings = (IBinding<Object>[]) Array.newInstance(IBinding.class, pParameterTypes.length); |
98 | 194 | for (int i = 0; i < bindings.length; i++) { |
99 | 74 | final Class<Object> cl = pParameterClasses[i]; |
100 | 74 | final Annotation[] annotations = pParameterAnnotations[i]; |
101 | 74 | bindings[i] = getBinding(cl, pParameterTypes[i], annotations, pBindings, pCause); |
102 | |
} |
103 | 120 | return bindings; |
104 | |
} |
105 | |
|
106 | |
private IBinding<Object> getBinding(Class<Object> pClass, Type pType, Annotation[] pAnnotations, IMutableBindingSource pBindings, String pCause) { |
107 | 138 | String name = Key.NO_NAME; |
108 | 230 | for (Annotation annotation : pAnnotations) { |
109 | 112 | if (annotation instanceof Named) { |
110 | 20 | name = ((Named) annotation).value(); |
111 | 20 | break; |
112 | |
} |
113 | |
} |
114 | 138 | if (pClass == PROVIDER_CLASS && pType != null && pType instanceof ParameterizedType) { |
115 | 46 | final ParameterizedType ptype = (ParameterizedType) pType; |
116 | 46 | final Type[] typeArgs = ptype.getActualTypeArguments(); |
117 | 46 | if (typeArgs != null && typeArgs.length == 1) { |
118 | 46 | final Type typeArg = typeArgs[0]; |
119 | 46 | if (typeArg instanceof Class<?>) { |
120 | |
@SuppressWarnings("unchecked") |
121 | 46 | final Class<Object> cl = (Class<Object>) typeArg; |
122 | 46 | final IKey<Object> key = new Key<Object>(cl, name); |
123 | 46 | final IBinding<Object> binding1 = pBindings.requireBinding(key, pCause); |
124 | 46 | final IProvider<Object> provider = new IProvider<Object>(){ |
125 | |
@Override |
126 | |
public Object get() { |
127 | 44 | return new Provider<Object>(){ |
128 | |
@Override |
129 | |
public Object get() { |
130 | 100 | return binding1.getProvider().get(); |
131 | |
} |
132 | |
}; |
133 | |
} |
134 | |
|
135 | |
@Override |
136 | |
public Class<? extends Object> getType() { |
137 | 0 | return Provider.class; |
138 | |
} |
139 | |
|
140 | |
@Override |
141 | |
public Object get(IInjector pInjector) { |
142 | 0 | return get(); |
143 | |
} |
144 | |
}; |
145 | 46 | final IPoint<Object> point = new IPoint<Object>(){ |
146 | |
@Override |
147 | |
public void injectTo(Object pInstance, |
148 | |
IInjector pInjector) { |
149 | |
|
150 | 0 | } |
151 | |
}; |
152 | 46 | final IBinding<Object> binding2 = new DefaultBinding<Object>(provider, point); |
153 | 46 | return binding2; |
154 | |
} |
155 | |
} |
156 | |
} |
157 | 92 | final IKey<Object> key = new Key<Object>(pClass, name); |
158 | 92 | return pBindings.requireBinding(key, pCause); |
159 | |
} |
160 | |
|
161 | |
public <T> ListPoint<T> getPoint(Class<T> pType, IMutableBindingSource pBindings) { |
162 | 48 | final List<IPoint<T>> points = new ArrayList<IPoint<T>>(); |
163 | 48 | final Field[] fields = pType.getDeclaredFields(); |
164 | 501 | for (final Field f : fields) { |
165 | 453 | if (Modifier.isStatic(f.getModifiers())) { |
166 | 127 | continue; |
167 | |
} |
168 | 326 | if (!f.isAnnotationPresent(Inject.class)) { |
169 | 262 | continue; |
170 | |
} |
171 | |
@SuppressWarnings("unchecked") |
172 | 64 | Class<Object> type = (Class<Object>) f.getType(); |
173 | 64 | Type genericType = f.getGenericType(); |
174 | 64 | IBinding<Object> binding = null; |
175 | 64 | Annotation[] annotations = f.getAnnotations(); |
176 | 64 | binding = getBinding(type, genericType, annotations, pBindings, |
177 | |
"Required to inject to an instance of " + pType.getName()); |
178 | 64 | final IPoint<T> point = new FieldPoint<T>(binding, f); |
179 | 64 | points.add(point); |
180 | |
} |
181 | 48 | final Method[] methods = pType.getDeclaredMethods(); |
182 | 638 | for (final Method m : methods) { |
183 | 590 | if (Modifier.isStatic(m.getModifiers())) { |
184 | 152 | continue; |
185 | |
} |
186 | 438 | if (!m.isAnnotationPresent(Inject.class)) { |
187 | 330 | continue; |
188 | |
} |
189 | |
@SuppressWarnings("unchecked") |
190 | 108 | Class<Object>[] parameterClasses = (Class<Object>[]) m.getParameterTypes(); |
191 | 108 | Type[] parameterTypes = m.getGenericParameterTypes(); |
192 | 108 | Annotation[][] annotations = m.getParameterAnnotations(); |
193 | 108 | final IBinding<Object>[] bindings = getBindings(parameterClasses, parameterTypes, annotations, pBindings, |
194 | |
"Required to inject to an instance of " + pType.getName()); |
195 | 108 | final IPoint<T> point = new MethodPoint<T>(bindings, m); |
196 | 108 | points.add(point); |
197 | |
} |
198 | 48 | return new ListPoint<T>(points); |
199 | |
} |
200 | |
} |