1
2
3
4 package net.sourceforge.pmd.lang.rule.properties;
5
6 import java.lang.reflect.Array;
7 import java.lang.reflect.Method;
8 import java.util.Map;
9
10 import net.sourceforge.pmd.PropertyDescriptorFactory;
11 import net.sourceforge.pmd.lang.rule.properties.factories.BasicPropertyDescriptorFactory;
12 import net.sourceforge.pmd.util.ClassUtil;
13 import net.sourceforge.pmd.util.StringUtil;
14
15
16
17
18
19
20
21
22
23
24 public class MethodProperty extends AbstractPackagedProperty<Method> {
25
26 public static final char CLASS_METHOD_DELIMITER = '#';
27 public static final char METHOD_ARG_DELIMITER = ',';
28 public static final char[] METHOD_GROUP_DELIMITERS = new char[] { '(', ')' };
29
30 private static final String ARRAY_FLAG = "[]";
31 private static final Map<Class<?>, String> TYPE_SHORTCUTS = ClassUtil.getClassShortNames();
32
33 public static final PropertyDescriptorFactory FACTORY = new BasicPropertyDescriptorFactory<MethodProperty>(Method.class, packagedFieldTypesByKey) {
34
35 public MethodProperty createWith(Map<String, String> valuesById) {
36 return new MethodProperty(
37 nameIn(valuesById),
38 descriptionIn(valuesById),
39 defaultValueIn(valuesById),
40 legalPackageNamesIn(valuesById),
41 0f);
42 }
43 };
44
45
46
47
48
49 private static String shortestNameFor(Class<?> cls) {
50 String compactName = TYPE_SHORTCUTS.get(cls);
51 return compactName == null ? cls.getName() : compactName;
52 }
53
54
55
56
57
58
59
60
61 public static String asStringFor(Method method) {
62 StringBuilder sb = new StringBuilder();
63 asStringOn(method, sb);
64 return sb.toString();
65 }
66
67
68
69
70 protected String defaultAsString() {
71 return asStringFor(defaultValue());
72 }
73
74
75
76
77 private static void serializedTypeIdOn(Class<?> type, StringBuilder sb) {
78
79 Class<?> arrayType = type.getComponentType();
80 if (arrayType == null) {
81 sb.append(shortestNameFor(type));
82 return;
83 }
84 sb.append(shortestNameFor(arrayType)).append(ARRAY_FLAG);
85 }
86
87
88
89
90
91
92
93 public static void asStringOn(Method method, StringBuilder sb) {
94
95 Class<?> clazz = method.getDeclaringClass();
96
97 sb.append(shortestNameFor(clazz));
98 sb.append(CLASS_METHOD_DELIMITER);
99 sb.append(method.getName());
100
101 sb.append(METHOD_GROUP_DELIMITERS[0]);
102
103 Class<?>[] argTypes = method.getParameterTypes();
104 if (argTypes.length == 0) {
105 sb.append(METHOD_GROUP_DELIMITERS[1]);
106 return;
107 }
108
109 serializedTypeIdOn(argTypes[0], sb);
110 for (int i = 1; i < argTypes.length; i++) {
111 sb.append(METHOD_ARG_DELIMITER);
112 serializedTypeIdOn(argTypes[i], sb);
113 }
114 sb.append(METHOD_GROUP_DELIMITERS[1]);
115 }
116
117
118
119
120
121 private static Class<?> typeFor(String typeName) {
122
123 Class<?> type = null;
124
125 if (typeName.endsWith(ARRAY_FLAG)) {
126 String arrayTypeName = typeName.substring(0, typeName.length() - ARRAY_FLAG.length());
127 type = typeFor(arrayTypeName);
128 return Array.newInstance(type, 0).getClass();
129 }
130
131 type = ClassUtil.getTypeFor(typeName);
132 if (type != null) {
133 return type;
134 }
135
136 try {
137 return Class.forName(typeName);
138 } catch (Exception ex) {
139 return null;
140 }
141 }
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165 public static Method methodFrom(String methodNameAndArgTypes, char classMethodDelimiter, char methodArgDelimiter) {
166
167
168
169
170 int delimPos0 = methodNameAndArgTypes.indexOf(classMethodDelimiter);
171 if (delimPos0 < 0) {
172 return null;
173 }
174
175 String className = methodNameAndArgTypes.substring(0, delimPos0);
176 Class<?> type = ClassUtil.getTypeFor(className);
177 if (type == null) {
178 return null;
179 }
180
181 int delimPos1 = methodNameAndArgTypes.indexOf(METHOD_GROUP_DELIMITERS[0]);
182 if (delimPos1 < 0) {
183 String methodName = methodNameAndArgTypes.substring(delimPos0 + 1);
184 return ClassUtil.methodFor(type, methodName, ClassUtil.EMPTY_CLASS_ARRAY);
185 }
186
187 String methodName = methodNameAndArgTypes.substring(delimPos0 + 1, delimPos1);
188 if (StringUtil.isEmpty(methodName)) {
189 return null;
190 }
191
192 int delimPos2 = methodNameAndArgTypes.indexOf(METHOD_GROUP_DELIMITERS[1]);
193 if (delimPos2 < 0) {
194 return null;
195 }
196
197 String argTypesStr = methodNameAndArgTypes.substring(delimPos1 + 1, delimPos2);
198 if (StringUtil.isEmpty(argTypesStr)) {
199 return ClassUtil.methodFor(type, methodName, ClassUtil.EMPTY_CLASS_ARRAY);
200 }
201
202 String[] argTypeNames = StringUtil.substringsOf(argTypesStr, methodArgDelimiter);
203 Class<?>[] argTypes = new Class[argTypeNames.length];
204 for (int i = 0; i < argTypes.length; i++) {
205 argTypes[i] = typeFor(argTypeNames[i]);
206 }
207
208 return ClassUtil.methodFor(type, methodName, argTypes);
209 }
210
211
212
213
214
215 public static Method methodFrom(String methodStr) {
216 return methodFrom(methodStr, CLASS_METHOD_DELIMITER, METHOD_ARG_DELIMITER);
217 }
218
219
220
221
222
223
224
225
226
227
228
229 public MethodProperty(String theName, String theDescription, Method theDefault, String[] legalPackageNames, float theUIOrder) {
230 super(theName, theDescription, theDefault, legalPackageNames, theUIOrder);
231 }
232
233
234
235
236
237
238
239
240
241
242
243 public MethodProperty(String theName, String theDescription, String defaultMethodStr, String[] legalPackageNames, float theUIOrder) {
244 super(theName, theDescription, methodFrom(defaultMethodStr), legalPackageNames, theUIOrder);
245 }
246
247
248
249
250
251
252
253
254
255
256
257 public MethodProperty(String theName, String theDescription, String defaultMethodStr, Map<String, String> otherParams, float theUIOrder) {
258 this(theName, theDescription, methodFrom(defaultMethodStr), packageNamesIn(otherParams), theUIOrder);
259 }
260
261
262
263
264
265
266
267
268 @Override
269 protected String asString(Object value) {
270 return value == null ? "" : asStringFor((Method) value);
271 }
272
273
274
275
276
277 @Override
278 protected String packageNameOf(Object item) {
279
280 final Method method = (Method) item;
281 return method.getDeclaringClass().getName() + '.' + method.getName();
282 }
283
284
285
286
287 @Override
288 protected String itemTypeName() {
289 return "method";
290 }
291
292
293
294
295
296 public Class<Method> type() {
297 return Method.class;
298 }
299
300
301
302
303
304
305
306 public Method valueFrom(String valueString) throws IllegalArgumentException {
307 return methodFrom(valueString);
308 }
309 }