1 package org.apache.commons.javaflow.bytecode.transformation;
2
3 import java.io.IOException;
4 import java.io.InputStream;
5
6 import org.apache.commons.io.IOUtils;
7 import org.apache.commons.javaflow.bytecode.BytecodeClassLoader;
8 import org.objectweb.asm.ClassReader;
9 import org.objectweb.asm.ClassWriter;
10 import org.objectweb.asm.Label;
11 import org.objectweb.asm.MethodVisitor;
12 import org.objectweb.asm.Opcodes;
13
14 public class ClassTransformerClassLoader extends BytecodeClassLoader {
15
16 private final ResourceTransformer transformer;
17 private final String prefix;
18
19 public ClassTransformerClassLoader(final ResourceTransformer pTransformer) {
20 this("org.apache.commons.javaflow.bytecode.transformation.", pTransformer);
21 }
22
23 public ClassTransformerClassLoader(final String pPrefix, final ResourceTransformer pTransformer) {
24 prefix = pPrefix;
25 transformer = pTransformer;
26 }
27
28 protected byte[] transform(final String pName, final InputStream pClassStream) throws IOException {
29 final byte[] oldClass = IOUtils.toByteArray(pClassStream);
30 final byte[] newClass = transformer.transform(oldClass);
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47 return newClass;
48 }
49
50
51 public Class loadLocalClass( final String name ) throws ClassNotFoundException {
52 return loadClass( prefix + name);
53 }
54
55
56 public Class createImplementationOf( final Class pAbstractClass ) {
57
58 final String base = pAbstractClass.getName().replace('.', '/');
59 final int slash = base.lastIndexOf('/');
60 final String packageName = base.substring(0, slash);
61 final String name = base.substring(packageName.length() + "Abstract".length() + 1);
62 final String extended = packageName + "/" + name + "Impl";
63
64 ClassWriter cw = new ClassWriter(true);
65 MethodVisitor mv;
66
67 cw.visit(Opcodes.V1_2, Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL + Opcodes.ACC_SUPER,
68 extended, null,
69 base, null);
70
71 cw.visitSource(name + "Impl.java", null);
72
73 mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null);
74 mv.visitCode();
75 Label l0 = new Label();
76 mv.visitLabel(l0);
77 mv.visitLineNumber(3, l0);
78 mv.visitVarInsn(Opcodes.ALOAD, 0);
79 mv.visitMethodInsn(Opcodes.INVOKESPECIAL,
80 base,
81 "<init>", "()V");
82 mv.visitInsn(Opcodes.RETURN);
83 Label l1 = new Label();
84 mv.visitLabel(l1);
85 mv.visitLocalVariable("this",
86 "L" + extended + ";",
87 null, l0, l1, 0);
88 mv.visitMaxs(1, 1);
89 mv.visitEnd();
90
91 cw.visitEnd();
92
93 return loadClass(cw.toByteArray());
94 }
95
96
97 public Class loadClass( final String name ) throws ClassNotFoundException {
98 if (name.startsWith(prefix)) {
99
100 try {
101 final InputStream is = getClass().getResourceAsStream(
102 "/" + name.replace('.', '/') + ".class");
103
104 byte[] bytecode;
105 if (name.indexOf(".rewrite.") >= 0) {
106
107
108 bytecode = transform(name, is);
109
110 } else {
111 ClassReader cr = new ClassReader(is);
112 bytecode = cr.b;
113 }
114
115 return super.defineClass(name, bytecode, 0, bytecode.length);
116
117 } catch (Throwable ex) {
118 System.err.println("Load error: " + ex.toString());
119 ex.printStackTrace();
120 throw new ClassNotFoundException(name + " " + ex.getMessage(), ex);
121 }
122 }
123
124 return super.loadClass(name);
125 }
126 }