1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.apache.ibatis.plugin;
17
18 import java.lang.reflect.InvocationHandler;
19 import java.lang.reflect.Method;
20 import java.lang.reflect.Proxy;
21 import java.util.HashMap;
22 import java.util.HashSet;
23 import java.util.Map;
24 import java.util.Set;
25
26 import org.apache.ibatis.reflection.ExceptionUtil;
27
28
29
30
31 public class Plugin implements InvocationHandler {
32
33 private final Object target;
34 private final Interceptor interceptor;
35 private final Map<Class<?>, Set<Method>> signatureMap;
36
37 private Plugin(Object target, Interceptor interceptor, Map<Class<?>, Set<Method>> signatureMap) {
38 this.target = target;
39 this.interceptor = interceptor;
40 this.signatureMap = signatureMap;
41 }
42
43 public static Object wrap(Object target, Interceptor interceptor) {
44 Map<Class<?>, Set<Method>> signatureMap = getSignatureMap(interceptor);
45 Class<?> type = target.getClass();
46 Class<?>[] interfaces = getAllInterfaces(type, signatureMap);
47 if (interfaces.length > 0) {
48 return Proxy.newProxyInstance(
49 type.getClassLoader(),
50 interfaces,
51 new Plugin(target, interceptor, signatureMap));
52 }
53 return target;
54 }
55
56 @Override
57 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
58 try {
59 Set<Method> methods = signatureMap.get(method.getDeclaringClass());
60 if (methods != null && methods.contains(method)) {
61 return interceptor.intercept(new Invocation(target, method, args));
62 }
63 return method.invoke(target, args);
64 } catch (Exception e) {
65 throw ExceptionUtil.unwrapThrowable(e);
66 }
67 }
68
69 private static Map<Class<?>, Set<Method>> getSignatureMap(Interceptor interceptor) {
70 Intercepts interceptsAnnotation = interceptor.getClass().getAnnotation(Intercepts.class);
71
72 if (interceptsAnnotation == null) {
73 throw new PluginException("No @Intercepts annotation was found in interceptor " + interceptor.getClass().getName());
74 }
75 Signature[] sigs = interceptsAnnotation.value();
76 Map<Class<?>, Set<Method>> signatureMap = new HashMap<>();
77 for (Signature sig : sigs) {
78 Set<Method> methods = signatureMap.computeIfAbsent(sig.type(), k -> new HashSet<>());
79 try {
80 Method method = sig.type().getMethod(sig.method(), sig.args());
81 methods.add(method);
82 } catch (NoSuchMethodException e) {
83 throw new PluginException("Could not find method on " + sig.type() + " named " + sig.method() + ". Cause: " + e, e);
84 }
85 }
86 return signatureMap;
87 }
88
89 private static Class<?>[] getAllInterfaces(Class<?> type, Map<Class<?>, Set<Method>> signatureMap) {
90 Set<Class<?>> interfaces = new HashSet<>();
91 while (type != null) {
92 for (Class<?> c : type.getInterfaces()) {
93 if (signatureMap.containsKey(c)) {
94 interfaces.add(c);
95 }
96 }
97 type = type.getSuperclass();
98 }
99 return interfaces.toArray(new Class<?>[interfaces.size()]);
100 }
101
102 }