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