1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 package org.modeshape.sequencer.classfile.metadata;
25
26 import java.util.ArrayList;
27 import java.util.Collections;
28 import java.util.LinkedList;
29 import java.util.List;
30 import javassist.bytecode.AccessFlag;
31 import javassist.bytecode.AnnotationsAttribute;
32 import javassist.bytecode.AttributeInfo;
33 import javassist.bytecode.ClassFile;
34 import javassist.bytecode.Descriptor;
35 import javassist.bytecode.MethodInfo;
36 import javassist.bytecode.annotation.Annotation;
37
38 public class MethodMetadata implements Comparable<MethodMetadata> {
39
40 private final MethodInfo method;
41 private final String name;
42 private final List<AnnotationMetadata> annotations;
43 private final List<String> parameters;
44
45 MethodMetadata( ClassFile clazz,
46 MethodInfo method ) {
47 this.method = method;
48 this.name = method.isConstructor() ? clazz.getName() : method.getName();
49 this.annotations = annotationsFor(method);
50 this.parameters = parametersFor(method);
51 }
52
53 private List<String> parametersFor( MethodInfo method ) {
54 String descriptor = method.getDescriptor();
55 int lastParenPos = descriptor.lastIndexOf(')');
56 assert lastParenPos >= 0;
57 String parameterString = descriptor.substring(1, lastParenPos);
58
59 if (parameterString.length() == 0) {
60 return Collections.emptyList();
61 }
62
63 List<String> parameters = new ArrayList<String>();
64 Descriptor.Iterator iter = new Descriptor.Iterator(parameterString);
65
66 assert iter.hasNext();
67 int startPos = iter.next();
68
69 while (iter.hasNext()) {
70 int endPos = iter.next();
71 parameters.add(Descriptor.toClassName(parameterString.substring(startPos, endPos)));
72 startPos = endPos;
73 }
74 parameters.add(Descriptor.toClassName(parameterString.substring(startPos)));
75
76 return parameters;
77 }
78
79 private String returnTypeFor( MethodInfo method ) {
80 String descriptor = method.getDescriptor();
81 int lastParenPos = descriptor.lastIndexOf(')');
82 assert lastParenPos >= 0;
83 return Descriptor.toClassName(descriptor.substring(lastParenPos + 1));
84 }
85
86 private List<AnnotationMetadata> annotationsFor( MethodInfo method ) {
87 List<AnnotationMetadata> annotations = new LinkedList<AnnotationMetadata>();
88
89 for (Object ob : method.getAttributes()) {
90 AttributeInfo att = (AttributeInfo)ob;
91
92 if (att instanceof AnnotationsAttribute) {
93 for (Annotation ann : ((AnnotationsAttribute)att).getAnnotations()) {
94 annotations.add(new AnnotationMetadata(ann));
95 }
96 }
97 }
98
99 return annotations;
100 }
101
102 private String shortNameFor( String type ) {
103 int lastDotPos = type.lastIndexOf('.');
104 if (lastDotPos < 0) return type;
105 return type.substring(lastDotPos + 1);
106 }
107
108 public String getName() {
109 return name;
110 }
111
112 public Visibility getVisibility() {
113 return Visibility.fromAccessFlags(method.getAccessFlags());
114 }
115
116 public boolean isConstructor() {
117 return method.isConstructor();
118 }
119
120 public String getReturnType() {
121 return returnTypeFor(method);
122 }
123
124 public List<AnnotationMetadata> getAnnotations() {
125 return annotations;
126 }
127
128 public List<String> getParameters() {
129 return parameters;
130 }
131
132 public boolean isStatic() {
133 return AccessFlag.STATIC == (AccessFlag.STATIC & method.getAccessFlags());
134 }
135
136 public boolean isFinal() {
137 return AccessFlag.FINAL == (AccessFlag.FINAL & method.getAccessFlags());
138 }
139
140 public boolean isAbstract() {
141 return AccessFlag.ABSTRACT == (AccessFlag.ABSTRACT & method.getAccessFlags());
142 }
143
144 public boolean isNative() {
145 return AccessFlag.NATIVE == (AccessFlag.NATIVE & method.getAccessFlags());
146 }
147
148 public boolean isStrictFp() {
149 return AccessFlag.STRICT == (AccessFlag.STRICT & method.getAccessFlags());
150 }
151
152 public boolean isSynchronized() {
153 return AccessFlag.SYNCHRONIZED == (AccessFlag.SYNCHRONIZED & method.getAccessFlags());
154 }
155
156 public int compareTo( MethodMetadata o ) {
157 if (this.isStatic() && !o.isStatic()) {
158 return -1;
159 }
160 if (!this.isStatic() && o.isStatic()) {
161 return 1;
162 }
163
164 if (!this.name.equals(o.name)) {
165 return this.name.compareTo(o.name);
166 }
167
168 if (this.parameters.size() != o.parameters.size()) {
169 return ((Integer)this.parameters.size()).compareTo(o.parameters.size());
170 }
171
172 for (int i = 0; i < parameters.size(); i++) {
173 String p1 = this.parameters.get(i);
174 String p2 = o.parameters.get(i);
175
176 if (!p1.equals(p2)) {
177 return p1.compareTo(p2);
178 }
179 }
180
181 return 0;
182 }
183
184 public String getId() {
185 StringBuilder buff = new StringBuilder();
186 buff.append(method.getName()).append('(');
187
188 boolean first = false;
189 for (String parameter : parameters) {
190 if (first) {
191 first = false;
192 } else {
193 buff.append(", ");
194 }
195 buff.append(shortNameFor(parameter).replace("[]", " array"));
196 }
197
198 buff.append(')');
199
200 return buff.toString();
201 }
202
203 @Override
204 public String toString() {
205 StringBuilder buff = new StringBuilder();
206
207 if (!annotations.isEmpty()) {
208 for (AnnotationMetadata annotation : annotations) {
209 buff.append(annotation).append("\n\t");
210 }
211 }
212
213 buff.append(getVisibility());
214 if (getVisibility() != Visibility.PACKAGE) buff.append(' ');
215
216 if (isFinal()) buff.append("final ");
217 if (isStatic()) buff.append("static ");
218
219 buff.append(shortNameFor(getReturnType())).append(' ');
220 buff.append(name).append('(');
221
222 boolean first = true;
223
224 for (String parameter : parameters) {
225 if (first) {
226 first = false;
227 } else {
228 buff.append(", ");
229 }
230 buff.append(shortNameFor(parameter));
231 }
232
233 buff.append(' ');
234
235 buff.append(");");
236
237 return buff.toString();
238 }
239
240 }