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