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.io.File;
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.AttributeInfo;
27 import javassist.bytecode.ClassFile;
28 import javassist.bytecode.FieldInfo;
29 import javassist.bytecode.InnerClassesAttribute;
30 import javassist.bytecode.MethodInfo;
31 import javassist.bytecode.annotation.Annotation;
32
33 import org.apache.commons.lang3.builder.EqualsBuilder;
34 import org.apache.commons.lang3.builder.HashCodeBuilder;
35 import org.jadira.scanner.classpath.ClasspathResolver;
36 import org.jadira.scanner.classpath.filter.JElementTypeFilter;
37 import org.jadira.scanner.classpath.filter.JTypeSubTypeOfFilter;
38 import org.jadira.scanner.classpath.projector.ClasspathProjector;
39 import org.jadira.scanner.classpath.visitor.IntrospectionVisitor;
40 import org.jadira.scanner.core.api.Projector;
41 import org.jadira.scanner.core.exception.ClasspathAccessException;
42
43 public class JClass extends JType {
44
45 private static final Projector<File> CLASSPATH_PROJECTOR = ClasspathProjector.SINGLETON;
46
47 protected JClass(String name, ClasspathResolver resolver) throws ClasspathAccessException {
48 this(findClassFile(name, resolver), resolver);
49 }
50
51 protected JClass(Class<?> clazz, ClasspathResolver resolver) throws ClasspathAccessException {
52 this(findClassFile(clazz.getName(), resolver), resolver);
53 }
54
55 protected JClass(ClassFile classFile, ClasspathResolver resolver) {
56 super(classFile, resolver);
57 }
58
59 public static JClass getJClass(String name, ClasspathResolver resolver) throws ClasspathAccessException {
60 return new JClass(name, resolver);
61 }
62
63 public static JClass getJClass(ClassFile classFile, ClasspathResolver resolver) {
64 return new JClass(classFile, resolver);
65 }
66
67 public static JClass getJClass(Class<?> clazz, ClasspathResolver resolver) throws ClasspathAccessException {
68 return new JClass(clazz, resolver);
69 }
70
71 public JClass getSuperType() throws ClasspathAccessException {
72
73 final String superClassFile = getClassFile().getSuperclass();
74 return JClass.getJClass(superClassFile, getResolver());
75 }
76
77 public List<JInterface> getImplementedInterfaces() throws ClasspathAccessException {
78
79 final List<JInterface> retVal = new ArrayList<JInterface>();
80 final String[] interfaces = getClassFile().getInterfaces();
81
82 for (String next : interfaces) {
83 retVal.add(JInterface.getJInterface(next, getResolver()));
84 }
85 return retVal;
86 }
87
88 @Override
89 public Class<?> getActualClass() throws ClasspathAccessException {
90
91 return getResolver().loadClass(getClassFile().getName());
92 }
93
94 public Set<JClass> getSubClasses() {
95
96 Set<JClass> retVal = new HashSet<JClass>();
97 List<? extends ClassFile> classes = getResolver().getClassFileResolver().resolveAll(null, CLASSPATH_PROJECTOR, new JTypeSubTypeOfFilter(this.getActualClass()), new JElementTypeFilter(JClass.class));
98 for (ClassFile classFile : classes) {
99 retVal.add(JClass.getJClass(classFile, getResolver()));
100 }
101 return retVal;
102 }
103
104 public List<JInnerClass> getEnclosedClasses() throws ClasspathAccessException {
105
106 final List<JInnerClass> retVal = new ArrayList<JInnerClass>();
107 @SuppressWarnings("unchecked")
108 List<AttributeInfo> attrs = (List<AttributeInfo>) getClassFile().getAttributes();
109 for (AttributeInfo next : attrs) {
110 if (next instanceof InnerClassesAttribute) {
111 int innerClassCount = ((InnerClassesAttribute) next).tableLength();
112 for (int i = 0; i < innerClassCount; i++) {
113 String innerName = ((InnerClassesAttribute) next).innerClass(i);
114
115 if (innerName != null && innerName.startsWith(this.getClassFile().getName())) {
116
117 ClassFile innerClass = findClassFile(innerName, getResolver());
118
119
120 if (innerClass != null) {
121 retVal.add(JInnerClass.getJInnerClass(this.getClassFile(), innerClass, getResolver()));
122 }
123 }
124 }
125 }
126 }
127 return retVal;
128 }
129
130 public List<JField> getFields() {
131
132 boolean isJavaLangThrowable = "java.lang.Throwable".equals(this.getName());
133 boolean isJavaLangSystem = "java.lang.System".equals(this.getName());
134
135 final List<JField> retVal = new ArrayList<JField>();
136 @SuppressWarnings("unchecked")
137 final List<FieldInfo> fields = (List<FieldInfo>) getClassFile().getFields();
138
139 for (FieldInfo next : fields) {
140 if (isJavaLangThrowable && ("backtrace".equals(next.getName()))) {
141
142 continue;
143 }
144 if (isJavaLangSystem && ("security".equals(next.getName()))) {
145 continue;
146 }
147 retVal.add(JField.getJField(next, this, getResolver()));
148 }
149 return retVal;
150 }
151
152 public List<JConstructor> getConstructors() throws ClasspathAccessException {
153
154 final List<JConstructor> retVal = new ArrayList<JConstructor>();
155 @SuppressWarnings("unchecked")
156 final List<MethodInfo> methods = (List<MethodInfo>) getClassFile().getMethods();
157
158 for (MethodInfo next : methods) {
159 if (next.isConstructor()) {
160 retVal.add(JConstructor.getJConstructor(next, this, getResolver()));
161 }
162 }
163
164 if (retVal.isEmpty()) {
165 retVal.add(JDefaultConstructor.getJConstructor((MethodInfo)null, (JClass)this, getResolver()));
166 }
167
168 return retVal;
169 }
170
171 @Override
172 public Set<JAnnotation<?>> getAnnotations() {
173
174 AnnotationsAttribute visible = (AnnotationsAttribute) getClassFile().getAttribute(AnnotationsAttribute.visibleTag);
175 AnnotationsAttribute invisible = (AnnotationsAttribute) getClassFile().getAttribute(AnnotationsAttribute.invisibleTag);
176
177 Set<JAnnotation<?>> annotations = new HashSet<JAnnotation<?>>();
178
179 List<Annotation> annotationsList = new ArrayList<Annotation>();
180 if (visible != null) {
181 annotationsList.addAll(Arrays.asList(visible.getAnnotations()));
182 }
183 if (invisible != null) {
184 annotationsList.addAll(Arrays.asList(invisible.getAnnotations()));
185 }
186
187 for (Annotation nextAnnotation : annotationsList) {
188 annotations.add(JAnnotation.getJAnnotation(nextAnnotation, this, getResolver()));
189 }
190
191 return annotations;
192 }
193
194 @Override
195 public JPackage getPackage() throws ClasspathAccessException {
196
197 String fqClassName = getClassFile().getName();
198
199 String packageName;
200 if (fqClassName.contains(".")) {
201 packageName = fqClassName.substring(0, fqClassName.lastIndexOf('.'));
202 } else {
203 packageName = "";
204 }
205
206 return JPackage.getJPackage(packageName, getResolver());
207 }
208
209 public List<JMethod> getMethods() {
210
211 final List<JMethod> retVal = new ArrayList<JMethod>();
212 @SuppressWarnings("unchecked")
213 final List<MethodInfo> methods = (List<MethodInfo>) getClassFile().getMethods();
214
215 for (MethodInfo next : methods) {
216 if (next.isMethod()) {
217 retVal.add(JMethod.getJMethod(next, this, getResolver()));
218 }
219 }
220 return retVal;
221 }
222
223 public List<JStaticInitializer> getStaticInitializers() {
224
225 final List<JStaticInitializer> retVal = new ArrayList<JStaticInitializer>();
226 @SuppressWarnings("unchecked")
227 final List<MethodInfo> methods = (List<MethodInfo>) getClassFile().getMethods();
228
229 for (MethodInfo next : methods) {
230 if (next.isStaticInitializer()) {
231 retVal.add(JStaticInitializer.getJStaticInitializer(next, this, getResolver()));
232 }
233 }
234 return retVal;
235 }
236
237 @Override
238 public void acceptVisitor(IntrospectionVisitor visitor) throws ClasspathAccessException {
239 visitor.visit(this);
240
241 for (JInterface next : getImplementedInterfaces()) {
242 next.acceptVisitor(visitor);
243 }
244 for (JInnerClass next : getEnclosedClasses()) {
245 next.acceptVisitor(visitor);
246 }
247 for (JField next : getFields()) {
248
249
250 if ("classLoader".equals(next.getName()) && "java.lang.Class".equals(next.getEnclosingType().getName())) {
251 continue;
252 }
253 next.acceptVisitor(visitor);
254 }
255 for (JConstructor next : getConstructors()) {
256 next.acceptVisitor(visitor);
257 }
258 for (JMethod next : getMethods()) {
259 next.acceptVisitor(visitor);
260 }
261 for (JStaticInitializer next : getStaticInitializers()) {
262 next.acceptVisitor(visitor);
263 }
264 for (JAnnotation<?> next : getAnnotations()) {
265 next.acceptVisitor(visitor);
266 }
267 }
268
269 @Override
270 public JElement getEnclosingElement() {
271 return getPackage();
272 }
273
274 public boolean isPrimitive() {
275 return false;
276 }
277
278 public boolean isArray() {
279 return false;
280 }
281
282 public boolean isInterface() {
283 return getClassFile().isInterface();
284 }
285
286 @Override
287 public boolean equals(Object obj) {
288 if (obj == null) {
289 return false;
290 }
291 if (obj == this) {
292 return true;
293 }
294 if (obj.getClass() != getClass()) {
295 return false;
296 }
297
298 return new EqualsBuilder()
299 .appendSuper(super.equals(obj))
300 .isEquals();
301 }
302
303 @Override
304 public int hashCode() {
305 return new HashCodeBuilder(11, 47).append(super.hashCode())
306 .toHashCode();
307 }
308 }