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(type.getClassLoader(), interfaces, new Plugin(target, interceptor, signatureMap));
50 }
51 return target;
52 }
53
54 @Override
55 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
56 try {
57 Set<Method> methods = signatureMap.get(method.getDeclaringClass());
58 if (methods != null && methods.contains(method)) {
59 return interceptor.intercept(new Invocation(target, method, args));
60 }
61 return method.invoke(target, args);
62 } catch (Exception e) {
63 throw ExceptionUtil.unwrapThrowable(e);
64 }
65 }
66
67 private static Map<Class<?>, Set<Method>> getSignatureMap(Interceptor interceptor) {
68 Intercepts interceptsAnnotation = interceptor.getClass().getAnnotation(Intercepts.class);
69
70 if (interceptsAnnotation == null) {
71 throw new PluginException(
72 "No @Intercepts annotation was found in interceptor " + interceptor.getClass().getName());
73 }
74 Signature[] sigs = interceptsAnnotation.value();
75 Map<Class<?>, Set<Method>> signatureMap = new HashMap<>();
76 for (Signature sig : sigs) {
77 Set<Method> methods = MapUtil.computeIfAbsent(signatureMap, sig.type(), k -> new HashSet<>());
78 try {
79 Method method = sig.type().getMethod(sig.method(), sig.args());
80 methods.add(method);
81 } catch (NoSuchMethodException e) {
82 throw new PluginException("Could not find method on " + sig.type() + " named " + sig.method() + ". Cause: " + e,
83 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<?>[0]);
100 }
101
102 }