1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.jadira.scanner.classpath.types;
17
18 import java.lang.reflect.Method;
19 import java.util.ArrayList;
20 import java.util.Arrays;
21 import java.util.HashSet;
22 import java.util.List;
23 import java.util.Set;
24
25 import javassist.bytecode.AnnotationsAttribute;
26 import javassist.bytecode.MethodInfo;
27 import javassist.bytecode.annotation.Annotation;
28
29 import org.apache.commons.lang3.builder.EqualsBuilder;
30 import org.apache.commons.lang3.builder.HashCodeBuilder;
31 import org.apache.commons.lang3.builder.ToStringBuilder;
32 import org.apache.commons.lang3.builder.ToStringStyle;
33 import org.jadira.scanner.classpath.ClasspathResolver;
34 import org.jadira.scanner.core.exception.ClasspathAccessException;
35 import org.jadira.scanner.core.helper.JavassistMethodInfoHelper;
36
37 public abstract class JOperation extends JElement {
38
39 private MethodInfo methodInfo;
40 private final JType enclosingType;
41
42 protected JOperation(MethodInfo methodInfo, JType enclosingType, ClasspathResolver resolver) {
43 super(methodInfo == null ? null : methodInfo.getName(), resolver);
44 this.methodInfo = methodInfo;
45 this.enclosingType = enclosingType;
46 }
47
48 public JType getEnclosingType() {
49 return enclosingType;
50 }
51
52 @Override
53 public Set<JAnnotation<?>> getAnnotations() {
54
55 AnnotationsAttribute visible = (AnnotationsAttribute) methodInfo.getAttribute(AnnotationsAttribute.visibleTag);
56 AnnotationsAttribute invisible = (AnnotationsAttribute) methodInfo.getAttribute(AnnotationsAttribute.invisibleTag);
57
58 Set<JAnnotation<?>> annotations = new HashSet<JAnnotation<?>>();
59
60 List<Annotation> annotationsList = new ArrayList<Annotation>();
61 if (visible != null) {
62 annotationsList.addAll(Arrays.asList(visible.getAnnotations()));
63 }
64 if (invisible != null) {
65 annotationsList.addAll(Arrays.asList(invisible.getAnnotations()));
66 }
67
68 for (Annotation nextAnnotation : annotationsList) {
69 annotations.add(JAnnotation.getJAnnotation(nextAnnotation, this, getResolver()));
70 }
71
72 return annotations;
73 }
74
75 @Override
76 public <A extends java.lang.annotation.Annotation> JAnnotation<A> getAnnotation(Class<A> annotation) {
77
78 AnnotationsAttribute visible = (AnnotationsAttribute) methodInfo.getAttribute(AnnotationsAttribute.visibleTag);
79 AnnotationsAttribute invisible = (AnnotationsAttribute) methodInfo.getAttribute(AnnotationsAttribute.invisibleTag);
80
81 List<javassist.bytecode.annotation.Annotation> annotationsList = new ArrayList<Annotation>();
82 if (visible != null) {
83 annotationsList.addAll(Arrays.asList(visible.getAnnotations()));
84 }
85 if (invisible != null) {
86 annotationsList.addAll(Arrays.asList(invisible.getAnnotations()));
87 }
88
89 for (javassist.bytecode.annotation.Annotation nextAnnotation : annotationsList) {
90 if (annotation.getName().equals(nextAnnotation.getTypeName())) {
91 @SuppressWarnings("unchecked") JAnnotation<A> retVal = (JAnnotation<A>) JAnnotation.getJAnnotation(nextAnnotation, this, getResolver());
92 return retVal;
93 }
94 }
95
96 return null;
97 }
98
99 protected MethodInfo getMethodInfo() {
100 return methodInfo;
101 }
102
103 public List<JParameter> getParameters() throws ClasspathAccessException {
104
105 List<JParameter> params = new ArrayList<JParameter>();
106 String[] paramTypes = JavassistMethodInfoHelper.getMethodParamTypeNames(methodInfo);
107 for (int i = 0; i < paramTypes.length; i++) {
108 params.add(JParameter.getJParameter(i, this, getResolver()));
109 }
110 return params;
111 }
112
113 public Method getActualMethod() throws ClasspathAccessException {
114
115 try {
116 return getEnclosingType().getActualClass().getMethod(getName(), getMethodParamClasses(methodInfo));
117 } catch (SecurityException e) {
118 throw new ClasspathAccessException("Problem obtaining method: " + e.getMessage(), e);
119 } catch (NoSuchMethodException e) {
120 throw new ClasspathAccessException("Problem finding method: " + e.getMessage(), e);
121 }
122 }
123
124
125
126
127
128 @Override
129 public JType getEnclosingElement() {
130 return enclosingType;
131 }
132
133 @Override
134 public String toString() {
135
136 ToStringBuilder builder = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE);
137 builder.append("name",this.getName());
138 builder.append("enclosingType",this.getEnclosingType());
139 builder.append("parameters",this.getParameters());
140
141 return builder.toString();
142 }
143
144 @Override
145 public boolean equals(Object obj) {
146 if (obj == null) {
147 return false;
148 }
149 if (obj == this) {
150 return true;
151 }
152 if (obj.getClass() != getClass()) {
153 return false;
154 }
155 JOperation rhs = (JOperation) obj;
156 return new EqualsBuilder()
157 .appendSuper(super.equals(obj))
158 .append(enclosingType, rhs.enclosingType).isEquals();
159 }
160
161 @Override
162 public int hashCode() {
163 return new HashCodeBuilder(11, 47).append(super.hashCode())
164 .append(enclosingType).toHashCode();
165 }
166
167
168 protected Class<?>[] getMethodParamClasses(MethodInfo methodInfo) throws ClasspathAccessException {
169
170 String[] classNames = JavassistMethodInfoHelper.getMethodParamTypeNames(methodInfo);
171 Class<?>[] retArray = new Class<?>[classNames.length];
172
173 for (int i = 0; i < classNames.length; i++) {
174 if (!"".equals(classNames[i])) {
175 retArray[i] = decodeFieldType(classNames[i]);
176 }
177 }
178 return retArray;
179 }
180
181 private Class<?> decodeFieldType(String componentType) {
182
183 char type = componentType.charAt(0);
184 String fieldContent = componentType.substring(1);
185
186 switch (type) {
187
188 case 'L':
189 return getResolver().loadClass(fieldContent.replace('/', '.'));
190
191 case 'B':
192 return Byte.class;
193
194 case 'C':
195 return Character.class;
196
197 case 'D':
198 return Double.class;
199
200 case 'F':
201 return Float.class;
202
203 case 'I':
204 return Integer.class;
205
206 case 'J':
207 return Long.class;
208
209 case 'S':
210 return Short.class;
211
212 case 'Z':
213 return Boolean.class;
214
215 case '[':
216 return Arrays.class;
217 }
218 return null;
219 }
220 }