1 package org.sourceforge.jemm.client;
2
3 import java.lang.reflect.Method;
4 import java.util.ArrayList;
5 import java.util.HashMap;
6 import java.util.List;
7 import java.util.Map;
8 import java.util.regex.Matcher;
9 import java.util.regex.Pattern;
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 public class Descriptor {
25 private static final Map<String, Class<?>> PRIMITIVE_TYPES = getPrimtiveTypesMap();
26 private static final Pattern DESCRIPTOR_PATTERN = Pattern.compile("((\\S+)#(\\S+)\\s+\\((.*)\\)(\\S+))");
27
28 private static final Pattern PARTIAL_PATTERN = Pattern.compile("(\\((.*)\\)(\\S+))");
29
30 private String className;
31 private String methodName;
32 private String[] parameterTypes;
33 private String returnType;
34
35 public Descriptor(String signature) throws DescriptorParsingException {
36 parse(signature);
37 }
38
39 public Descriptor(String className, String methodName, String returnType,String... parameters) {
40 this.className =className;
41 this.methodName = methodName;
42 this.returnType = returnType;
43 this.parameterTypes = parameters;
44 }
45
46 public Descriptor(String className,String methodName, String signature) {
47 this.className =className;
48 this.methodName = methodName;
49 parsePartial(signature);
50 }
51
52 private void parsePartial(String signature) {
53 try {
54 Matcher m = PARTIAL_PATTERN.matcher(signature);
55 if(m.matches()) {
56 String parameters = m.group(2);
57 parameterTypes = extractTypesFromParameterString(parameters);
58 returnType = m.group(3);
59 } else {
60 throw new DescriptorParsingException("Descriptor (" + signature +") is invalid");
61 }
62 } catch(Exception e) {
63 throw new DescriptorParsingException("Descriptor (" + signature +") is invalid",e);
64 }
65 }
66
67 private void parse(String signature) {
68 try {
69 Matcher m = DESCRIPTOR_PATTERN.matcher(signature);
70 if(m.matches()) {
71 className = m.group(2);
72 methodName = m.group(3);
73 String parameters = m.group(4);
74 parameterTypes = extractTypesFromParameterString(parameters);
75 returnType = m.group(5);
76 } else {
77 throw new DescriptorParsingException("Descriptor (" + signature +") is invalid");
78 }
79 } catch(Exception e) {
80 throw new DescriptorParsingException("Descriptor (" + signature +") is invalid",e);
81 }
82 }
83
84 public String getClassName() {
85 return className;
86 }
87
88 public Class<?> getClassContainingMethod() throws ClassNotFoundException {
89 return Class.forName(getClassName());
90 }
91
92 public Method getMethod() throws SecurityException, NoSuchMethodException, ClassNotFoundException {
93 return getClassContainingMethod().getDeclaredMethod(getMethodName(), getParameterClasses());
94 }
95
96 public String getMethodName() {
97 return methodName;
98 }
99
100 private String [] extractTypesFromParameterString(String pString) {
101 List<String> results = new ArrayList<String>();
102
103 int i = 0;
104
105 while (i < pString.length()) {
106 String array = readArrayBraces(pString, i);
107 String type = readType(pString, i + array.length());
108
109 results.add(array + type);
110 i += array.length() + type.length();
111 }
112 return results.toArray(new String[results.size()]);
113 }
114
115 public String[] getParameterStrings() {
116 return parameterTypes;
117 }
118
119
120
121
122
123
124
125
126 private String readType(String pString, int start) {
127 if (pString.charAt(start) == 'L') {
128 int objectNameEndPos = pString.indexOf(";", start);
129 return convertClassName(pString.substring(start,
130 objectNameEndPos + 1));
131 } else {
132 return pString.substring(start, start + 1);
133 }
134 }
135
136
137
138
139
140
141
142
143
144
145
146 private String readArrayBraces(String pString, int start) {
147 int end = start;
148 for (int j = start; j < pString.length(); ++j) {
149 if (pString.charAt(j) != '[') {
150 end = j;
151 break;
152 }
153 }
154 return pString.substring(start, end);
155 }
156
157
158
159
160
161
162
163
164 private String convertClassName(String classWithSlashes) {
165 return classWithSlashes.replace('/', '.');
166 }
167
168 public String getReturnString() {
169 return returnType;
170 }
171
172 public Class<?> getReturnClass() throws ClassNotFoundException {
173 return getType(getReturnString());
174 }
175
176 public Class<?>[] getParameterClasses() throws ClassNotFoundException {
177 String[] pStrings = getParameterStrings();
178 List<Class<?>> results = new ArrayList<Class<?>>();
179 for (int i = 0; i < pStrings.length; ++i) {
180 results.add(getType(pStrings[i]));
181 }
182 if(containsJustVoid(results))
183 return new Class[0];
184
185 return results.toArray(new Class[results.size()]);
186 }
187
188 private boolean containsJustVoid(List<Class<?>> results) {
189 if(results.size()>1 || results.size()==0)
190 return false;
191 if(Void.TYPE.equals(results.get(0)))
192 return true;
193
194 return false;
195 }
196
197 public Class<?> getType(String typeName) throws ClassNotFoundException {
198 if (PRIMITIVE_TYPES.containsKey(typeName)) {
199 return PRIMITIVE_TYPES.get(typeName);
200 } else {
201 Class<?> clazz = Class.forName(cleanClassName(typeName));
202 return clazz;
203 }
204 }
205
206
207
208
209
210
211
212
213 protected String cleanClassName(String aClassName) {
214 if (aClassName.startsWith("L") && aClassName.endsWith(";"))
215 return aClassName.substring(1, aClassName.length() - 1);
216 else
217 return aClassName;
218 }
219
220 private String getParameterString() {
221 StringBuffer sb = new StringBuffer();
222 for(int i=0; i<parameterTypes.length; ++i)
223 sb.append(parameterTypes[i]);
224
225 return sb.toString();
226 }
227
228 public String getDescriptorString() {
229 return className + "#" +methodName+" ("+getParameterString()+")"+returnType;
230 }
231
232 public int hashCode() {
233 return getDescriptorString().hashCode();
234 }
235
236 public boolean equals(Object obj) {
237 if(!(obj instanceof Descriptor))
238 return false;
239
240 Descriptor rhs = (Descriptor)obj;
241 return getDescriptorString().equals(rhs.getDescriptorString());
242 }
243
244 public String toString() {
245 return getDescriptorString();
246 }
247
248 public static Map<String, Class<?>> getPrimtiveTypesMap() {
249 Map<String, Class<?>> m = new HashMap<String, Class<?>>();
250 m.put("B", Byte.TYPE);
251 m.put("C", Character.TYPE);
252 m.put("D", Double.TYPE);
253 m.put("F", Float.TYPE);
254 m.put("I", Integer.TYPE);
255 m.put("J", Long.TYPE);
256 m.put("S", Short.TYPE);
257 m.put("Z", Boolean.TYPE);
258 m.put("V", Void.TYPE);
259
260 return m;
261 }
262 }