View Javadoc

1   /*
2    * ModeShape (http://www.modeshape.org)
3    * See the COPYRIGHT.txt file distributed with this work for information
4    * regarding copyright ownership.  Some portions may be licensed
5    * to Red Hat, Inc. under one or more contributor license agreements.
6    * See the AUTHORS.txt file in the distribution for a full listing of 
7    * individual contributors. 
8    *
9    * ModeShape is free software. Unless otherwise indicated, all code in ModeShape
10   * is licensed to you under the terms of the GNU Lesser General Public License as
11   * published by the Free Software Foundation; either version 2.1 of
12   * the License, or (at your option) any later version.
13   *
14   * ModeShape is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17   * Lesser General Public License for more details.
18   *
19   * You should have received a copy of the GNU Lesser General Public
20   * License along with this software; if not, write to the Free
21   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
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 }