1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 */ 18 19 import java.awt.event.ActionEvent; 20 import java.awt.event.ActionListener; 21 22 import org.apache.bcel.Constants; 23 import org.apache.bcel.classfile.Utility; 24 import org.apache.bcel.generic.ALOAD; 25 import org.apache.bcel.generic.ClassGen; 26 import org.apache.bcel.generic.ConstantPoolGen; 27 import org.apache.bcel.generic.GETSTATIC; 28 import org.apache.bcel.generic.INVOKEVIRTUAL; 29 import org.apache.bcel.generic.InstructionConstants; 30 import org.apache.bcel.generic.InstructionFactory; 31 import org.apache.bcel.generic.InstructionList; 32 import org.apache.bcel.generic.MethodGen; 33 import org.apache.bcel.generic.ObjectType; 34 import org.apache.bcel.generic.PUSH; 35 import org.apache.bcel.generic.Type; 36 37 /** 38 * Dynamically creates and uses a proxy for {@code java.awt.event.ActionListener} 39 * via the classloader mechanism if called with 40 * <pre>java org.apache.bcel.util.JavaWrapper ProxyCreator</pre> 41 * 42 * The trick is to encode the byte code we need into the class name 43 * using the Utility.encode() method. This will result however in big 44 * ugly class name, so for many cases it will be more sufficient to 45 * put some clever creation code into the class loader.<br> This is 46 * comparable to the mechanism provided via 47 * {@code java.lang.reflect.Proxy}, but much more flexible. 48 * 49 * @version $Id$ 50 * @see org.apache.bcel.util.JavaWrapper 51 * @see Utility 52 */ 53 public class ProxyCreator { 54 55 /** 56 * Load class and create instance 57 */ createProxy(String pack, String class_name)58 public static Object createProxy(String pack, String class_name) { 59 try { 60 Class<?> cl = Class.forName(pack + "$$BCEL$$" + class_name); 61 return cl.newInstance(); 62 } catch (Exception e) { 63 e.printStackTrace(); 64 } 65 66 return null; 67 } 68 69 /** 70 * Create JavaClass object for a simple proxy for an java.awt.event.ActionListener 71 * that just prints the passed arguments, load and use it via the class loader 72 * mechanism. 73 */ main(String[] argv)74 public static void main(String[] argv) throws Exception { 75 ClassLoader loader = ProxyCreator.class.getClassLoader(); 76 77 // instanceof won't work here ... 78 // TODO this is broken; cannot ever be true now that ClassLoader has been dropped 79 if (loader.getClass().toString().equals("class org.apache.bcel.util.ClassLoader")) { 80 // Real class name will be set by the class loader 81 ClassGen cg = new ClassGen("foo", "java.lang.Object", "", Constants.ACC_PUBLIC, 82 new String[]{"java.awt.event.ActionListener"}); 83 84 // That's important, otherwise newInstance() won't work 85 cg.addEmptyConstructor(Constants.ACC_PUBLIC); 86 87 InstructionList il = new InstructionList(); 88 ConstantPoolGen cp = cg.getConstantPool(); 89 InstructionFactory factory = new InstructionFactory(cg); 90 91 int out = cp.addFieldref("java.lang.System", "out", 92 "Ljava/io/PrintStream;"); 93 int println = cp.addMethodref("java.io.PrintStream", "println", 94 "(Ljava/lang/Object;)V"); 95 MethodGen mg = new MethodGen(Constants.ACC_PUBLIC, Type.VOID, 96 new Type[]{ 97 new ObjectType("java.awt.event.ActionEvent") 98 }, null, "actionPerformed", "foo", il, cp); 99 100 // System.out.println("actionPerformed:" + event); 101 il.append(new GETSTATIC(out)); 102 il.append(factory.createNew("java.lang.StringBuffer")); 103 il.append(InstructionConstants.DUP); 104 il.append(new PUSH(cp, "actionPerformed:")); 105 il.append(factory.createInvoke("java.lang.StringBuffer", "<init>", Type.VOID, 106 new Type[]{Type.STRING}, Constants.INVOKESPECIAL)); 107 108 il.append(new ALOAD(1)); 109 il.append(factory.createAppend(Type.OBJECT)); 110 il.append(new INVOKEVIRTUAL(println)); 111 il.append(InstructionConstants.RETURN); 112 113 mg.stripAttributes(true); 114 mg.setMaxStack(); 115 mg.setMaxLocals(); 116 cg.addMethod(mg.getMethod()); 117 118 byte[] bytes = cg.getJavaClass().getBytes(); 119 120 System.out.println("Uncompressed class: " + bytes.length); 121 122 String s = Utility.encode(bytes, true); 123 System.out.println("Encoded class: " + s.length()); 124 125 System.out.print("Creating proxy ... "); 126 ActionListener a = (ActionListener) createProxy("foo.bar.", s); 127 System.out.println("Done. Now calling actionPerformed()"); 128 129 a.actionPerformed(new ActionEvent(a, ActionEvent.ACTION_PERFORMED, "hello")); 130 } else { 131 System.err.println("Call me with java org.apache.bcel.util.JavaWrapper ProxyCreator"); 132 } 133 } 134 135 } 136