1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.proxy2.stub;
18
19 import java.io.Serializable;
20 import java.lang.annotation.Annotation;
21 import java.lang.reflect.InvocationHandler;
22 import java.lang.reflect.InvocationTargetException;
23 import java.lang.reflect.Method;
24 import java.lang.reflect.Proxy;
25 import java.util.Map;
26
27 import org.apache.commons.lang3.AnnotationUtils;
28 import org.apache.commons.lang3.ArrayUtils;
29 import org.apache.commons.lang3.ObjectUtils;
30 import org.apache.commons.lang3.Validate;
31 import org.apache.commons.lang3.reflect.TypeUtils;
32 import org.apache.commons.proxy2.Interceptor;
33 import org.apache.commons.proxy2.Invocation;
34 import org.apache.commons.proxy2.Invoker;
35 import org.apache.commons.proxy2.ObjectProvider;
36 import org.apache.commons.proxy2.ProxyFactory;
37 import org.apache.commons.proxy2.ProxyUtils;
38 import org.apache.commons.proxy2.impl.AbstractProxyFactory;
39 import org.apache.commons.proxy2.provider.ObjectProviderUtils;
40
41 public class AnnotationBuilder<A extends Annotation> extends StubBuilder<A>
42 {
43
44
45
46 private static class InterceptorInvocationHandler implements InvocationHandler, Serializable
47 {
48
49 private static final long serialVersionUID = 1L;
50
51 private final ObjectProvider<?> provider;
52 private final Interceptor methodInterceptor;
53
54 public InterceptorInvocationHandler(ObjectProvider<?> provider, Interceptor methodInterceptor)
55 {
56 this.provider = provider;
57 this.methodInterceptor = methodInterceptor;
58 }
59
60
61
62
63 @Override
64 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
65 {
66 if (ProxyUtils.isHashCode(method))
67 {
68 return Integer.valueOf(AnnotationUtils.hashCode((Annotation) proxy));
69 }
70 if (ProxyUtils.isEqualsMethod(method))
71 {
72 return Boolean.valueOf(args[0] instanceof Annotation
73 && AnnotationUtils.equals((Annotation) proxy, (Annotation) args[0]));
74 }
75 if ("toString".equals(method.getName()) && method.getParameterTypes().length == 0)
76 {
77 return AnnotationUtils.toString((Annotation) proxy);
78 }
79 final ReflectionInvocation invocation = new ReflectionInvocation(provider.getObject(), method, args);
80 return methodInterceptor.intercept(invocation);
81 }
82
83 }
84
85 private static class ReflectionInvocation implements Invocation
86 {
87 private final Method method;
88 private final Object[] arguments;
89 private final Object target;
90
91 public ReflectionInvocation(Object target, Method method, Object[] arguments)
92 {
93 this.method = method;
94 this.arguments = ObjectUtils.defaultIfNull(ArrayUtils.clone(arguments), ProxyUtils.EMPTY_ARGUMENTS);
95 this.target = target;
96 }
97
98 @Override
99 public Object[] getArguments()
100 {
101 return arguments;
102 }
103
104 @Override
105 public Method getMethod()
106 {
107 return method;
108 }
109
110 @Override
111 public Object getProxy()
112 {
113 return target;
114 }
115
116 @Override
117 public Object proceed() throws Throwable
118 {
119 try
120 {
121 return method.invoke(target, arguments);
122 }
123 catch (InvocationTargetException e)
124 {
125 throw e.getTargetException();
126 }
127 }
128 }
129
130 private static final ProxyFactory PROXY_FACTORY = new AbstractProxyFactory()
131 {
132 @Override
133 public <T> T createInvokerProxy(ClassLoader classLoader, final Invoker invoker, Class<?>... proxyClasses)
134 {
135 @SuppressWarnings("unchecked")
136 final T result = (T) Proxy.newProxyInstance(classLoader, proxyClasses, new InvocationHandler()
137 {
138 @Override
139 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
140 {
141 return invoker.invoke(proxy, method, args);
142 }
143 });
144 return result;
145 }
146
147 @Override
148 public <T> T createInterceptorProxy(ClassLoader classLoader, Object target, Interceptor interceptor,
149 Class<?>... proxyClasses)
150 {
151 @SuppressWarnings("unchecked")
152 final T result = (T) Proxy.newProxyInstance(classLoader, proxyClasses, new InterceptorInvocationHandler(
153 ObjectProviderUtils.constant(target), interceptor));
154 return result;
155 }
156
157 @Override
158 public <T> T createDelegatorProxy(ClassLoader classLoader, final ObjectProvider<?> delegateProvider,
159 Class<?>... proxyClasses)
160 {
161 @SuppressWarnings("unchecked")
162 final T result = (T) Proxy.newProxyInstance(classLoader, proxyClasses, new InterceptorInvocationHandler(
163 delegateProvider, new Interceptor()
164 {
165 private static final long serialVersionUID = 1L;
166
167 @Override
168 public Object intercept(Invocation invocation) throws Throwable
169 {
170 return invocation.proceed();
171 }
172 }));
173 return result;
174 }
175 };
176
177 private class MapAnnotationTrainer extends AnnotationTrainer<A>
178 {
179 private final Map<String, ?> members;
180
181 MapAnnotationTrainer(Map<String, ?> members)
182 {
183 super(annotationType);
184 this.members = members;
185 }
186
187 @Override
188 protected void train(A trainee)
189 {
190 WhenObject<Object> bud;
191 AnnotationTrainer<A> dy = this;
192 for (Map.Entry<String, ?> attr : members.entrySet())
193 {
194 final Method m;
195 try
196 {
197 m = traineeType.getDeclaredMethod(attr.getKey());
198 }
199 catch (Exception e1)
200 {
201 throw new IllegalArgumentException(String.format("Could not detect annotation member %1$s",
202 attr.getKey()));
203 }
204 try
205 {
206 bud = dy.when(m.invoke(trainee));
207 }
208 catch (Exception e)
209 {
210
211
212 continue;
213 }
214 final Object value = attr.getValue();
215 Validate.isTrue(TypeUtils.isInstance(value, m.getReturnType()), "Value %s can not be assigned to %s",
216 value, m.getReturnType());
217 dy = bud.thenReturn(value);
218 }
219 }
220 }
221
222 public static <A extends Annotation> A buildDefault(Class<A> type)
223 {
224 return of(type).build();
225 }
226
227 public static <A extends Annotation> AnnotationBuilder<A> of(Class<A> type)
228 {
229 return new AnnotationBuilder<A>(type, AnnotationInvoker.INSTANCE);
230 }
231
232 public static <A extends Annotation> AnnotationBuilder<A> of(Class<A> type, ObjectProvider<? extends A> provider)
233 {
234 return new AnnotationBuilder<A>(type, provider);
235 }
236
237 public static <A extends Annotation> AnnotationBuilder<A> of(Class<A> type, A target)
238 {
239 return new AnnotationBuilder<A>(type, target);
240 }
241
242 private final Class<A> annotationType;
243
244 private AnnotationBuilder(Class<A> type, Invoker invoker)
245 {
246 super(PROXY_FACTORY, type, invoker);
247 this.annotationType = type;
248 train(new AnnotationTypeTrainer<A>(type));
249 }
250
251 private AnnotationBuilder(Class<A> type, ObjectProvider<? extends A> provider)
252 {
253 super(PROXY_FACTORY, type, provider);
254 this.annotationType = type;
255 train(new AnnotationTypeTrainer<A>(type));
256 }
257
258 private AnnotationBuilder(Class<A> type, A target)
259 {
260 super(PROXY_FACTORY, type, target);
261 this.annotationType = type;
262 train(new AnnotationTypeTrainer<A>(type));
263 }
264
265 public AnnotationBuilder<A> withMembers(Map<String, ?> members)
266 {
267 return train(new MapAnnotationTrainer(members));
268 }
269
270 @Override
271 public <O> AnnotationBuilder<A> train(BaseTrainer<?, O> trainer)
272 {
273 return (AnnotationBuilder<A>) super.train(trainer);
274 }
275 }