1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.apache.ibatis.reflection;
17
18 import java.lang.annotation.Annotation;
19 import java.lang.reflect.Method;
20 import java.util.Collection;
21 import java.util.Collections;
22 import java.util.List;
23 import java.util.Map;
24 import java.util.Optional;
25 import java.util.SortedMap;
26 import java.util.TreeMap;
27
28 import org.apache.ibatis.annotations.Param;
29 import org.apache.ibatis.binding.MapperMethod.ParamMap;
30 import org.apache.ibatis.session.Configuration;
31 import org.apache.ibatis.session.ResultHandler;
32 import org.apache.ibatis.session.RowBounds;
33
34 public class ParamNameResolver {
35
36 public static final String GENERIC_NAME_PREFIX = "param";
37
38 public static final String[] GENERIC_NAME_CACHE = new String[10];
39
40 static {
41 for (int i = 0; i < 10; i++) {
42 GENERIC_NAME_CACHE[i] = GENERIC_NAME_PREFIX + (i + 1);
43 }
44 }
45
46 private final boolean useActualParamName;
47
48
49
50
51
52
53
54
55
56
57
58
59 private final SortedMap<Integer, String> names;
60
61 private boolean hasParamAnnotation;
62
63 public ParamNameResolver(Configuration config, Method method) {
64 this.useActualParamName = config.isUseActualParamName();
65 final Class<?>[] paramTypes = method.getParameterTypes();
66 final Annotation[][] paramAnnotations = method.getParameterAnnotations();
67 final SortedMap<Integer, String> map = new TreeMap<>();
68 int paramCount = paramAnnotations.length;
69
70 for (int paramIndex = 0; paramIndex < paramCount; paramIndex++) {
71 if (isSpecialParameter(paramTypes[paramIndex])) {
72
73 continue;
74 }
75 String name = null;
76 for (Annotation annotation : paramAnnotations[paramIndex]) {
77 if (annotation instanceof Param) {
78 hasParamAnnotation = true;
79 name = ((Param) annotation).value();
80 break;
81 }
82 }
83 if (name == null) {
84
85 if (useActualParamName) {
86 name = getActualParamName(method, paramIndex);
87 }
88 if (name == null) {
89
90
91 name = String.valueOf(map.size());
92 }
93 }
94 map.put(paramIndex, name);
95 }
96 names = Collections.unmodifiableSortedMap(map);
97 }
98
99 private String getActualParamName(Method method, int paramIndex) {
100 return ParamNameUtil.getParamNames(method).get(paramIndex);
101 }
102
103 private static boolean isSpecialParameter(Class<?> clazz) {
104 return RowBounds.class.isAssignableFrom(clazz) || ResultHandler.class.isAssignableFrom(clazz);
105 }
106
107
108
109
110
111
112 public String[] getNames() {
113 return names.values().toArray(new String[0]);
114 }
115
116
117
118
119
120
121
122
123
124
125 public Object getNamedParams(Object[] args) {
126 final int paramCount = names.size();
127 if (args == null || paramCount == 0) {
128 return null;
129 }
130 if (!hasParamAnnotation && paramCount == 1) {
131 Object value = args[names.firstKey()];
132 return wrapToMapIfCollection(value, useActualParamName ? names.get(names.firstKey()) : null);
133 } else {
134 final Map<String, Object> param = new ParamMap<>();
135 int i = 0;
136 for (Map.Entry<Integer, String> entry : names.entrySet()) {
137 param.put(entry.getValue(), args[entry.getKey()]);
138
139 final String genericParamName = i < 10 ? GENERIC_NAME_CACHE[i] : GENERIC_NAME_PREFIX + (i + 1);
140
141 if (!names.containsValue(genericParamName)) {
142 param.put(genericParamName, args[entry.getKey()]);
143 }
144 i++;
145 }
146 return param;
147 }
148 }
149
150
151
152
153
154
155
156
157
158
159
160
161
162 public static Object wrapToMapIfCollection(Object object, String actualParamName) {
163 if (object instanceof Collection) {
164 ParamMap<Object> map = new ParamMap<>();
165 map.put("collection", object);
166 if (object instanceof List) {
167 map.put("list", object);
168 }
169 Optional.ofNullable(actualParamName).ifPresent(name -> map.put(name, object));
170 return map;
171 }
172 if (object != null && object.getClass().isArray()) {
173 ParamMap<Object> map = new ParamMap<>();
174 map.put("array", object);
175 Optional.ofNullable(actualParamName).ifPresent(name -> map.put(name, object));
176 return map;
177 }
178 return object;
179 }
180
181 }