1 /***
2 * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3 */
4 package net.sourceforge.pmd.typeresolution;
5
6 import net.sourceforge.pmd.typeresolution.visitors.PMDASMVisitor;
7
8 import org.objectweb.asm.ClassReader;
9 import org.objectweb.asm.ClassWriter;
10
11 import java.io.IOException;
12 import java.util.HashMap;
13 import java.util.HashSet;
14 import java.util.List;
15 import java.util.Map;
16 import java.util.Set;
17
18 public class PMDASMClassLoader extends ClassLoader {
19
20 public PMDASMClassLoader() {
21 }
22
23 public synchronized Class loadClass(String name) throws ClassNotFoundException {
24 return defineClass(name);
25 }
26
27 private Map importedClasses = new HashMap();
28
29 private Set dontBother = new HashSet();
30
31 public Map getImportedClasses(String className) {
32 Map ret = (Map) importedClasses.get(className);
33 return ret == null ? new HashMap() : ret;
34 }
35
36 private Class defineClass(String name) throws ClassNotFoundException {
37
38 if (dontBother.contains(name)) {
39 throw new ClassNotFoundException(name);
40 }
41 try {
42 if (name.startsWith("java.")) {
43 return Class.forName(name);
44 }
45 if (importedClasses.containsKey(name)) {
46 if (super.findLoadedClass(name) != null) {
47 return super.findLoadedClass(name);
48 }
49 }
50 ClassReader reader = new ClassReader(getResourceAsStream(name.replace('.', '/') + ".class"));
51 PMDASMVisitor asmVisitor = new PMDASMVisitor();
52 reader.accept(asmVisitor, 0);
53
54 List inner = asmVisitor.getInnerClasses();
55 if (inner != null && !inner.isEmpty()) {
56 for (int ix = 0; ix < inner.size(); ix++) {
57 String str = (String) inner.get(ix);
58 ClassReader innerReader = new ClassReader(getResourceAsStream(str.replace('.', '/') + ".class"));
59 innerReader.accept(asmVisitor, 0);
60 }
61 }
62 importedClasses.put(name, asmVisitor.getPackages());
63 ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS);
64 reader.accept(writer, 0);
65
66 byte[] byteCode = writer.toByteArray();
67 return defineClass(name, byteCode, 0, byteCode.length);
68 } catch (ClassNotFoundException e) {
69 dontBother.add(name);
70 throw e;
71 } catch (IOException e) {
72 dontBother.add(name);
73 throw new ClassNotFoundException(name, e);
74 }
75 }
76 }